mirror of
https://github.com/apache/impala.git
synced 2025-12-25 02:03:09 -05:00
This change adds get_workload() to ImpalaTestSuite and removes it from all test suites that already returned 'functional-query'. get_workload() is also removed from CustomClusterTestSuite which used to return 'tpch'. All other changes besides impala_test_suite.py and custom_cluster_test_suite.py are just mass removals of get_workload() functions. The behavior is only changed in custom cluster tests that didn't override get_workload(). By returning 'functional-query' instead of 'tpch', exploration_strategy() will no longer return 'core' in 'exhaustive' test runs. See IMPALA-3947 on why workload affected exploration_strategy. An example for affected test is TestCatalogHMSFailures which was skipped both in core and exhaustive runs before this change. get_workload() functions that return a different workload than 'functional-query' are not changed - it is possible that some of these also don't handle exploration_strategy() as expected, but individually checking these tests is out of scope in this patch. Change-Id: I9ec6c41ffb3a30e1ea2de773626d1485c69fe115 Reviewed-on: http://gerrit.cloudera.org:8080/22726 Reviewed-by: Riza Suminto <riza.suminto@cloudera.com> Reviewed-by: Daniel Becker <daniel.becker@cloudera.com> Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
458 lines
21 KiB
Python
458 lines
21 KiB
Python
# 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.
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
from builtins import range
|
|
import os
|
|
import pytest
|
|
from hive_metastore.ttypes import (
|
|
ColumnStatistics, ColumnStatisticsDesc, ColumnStatisticsData,
|
|
ColumnStatisticsObj, StringColumnStatsData)
|
|
|
|
from tests.common.environ import ImpalaTestClusterProperties
|
|
from tests.common.impala_cluster import ImpalaCluster
|
|
from tests.common.impala_test_suite import ImpalaTestSuite
|
|
from tests.common.skip import SkipIfFS, SkipIfLocal, SkipIfCatalogV2
|
|
from tests.common.test_dimensions import (
|
|
create_exec_option_dimension,
|
|
create_single_exec_option_dimension,
|
|
create_uncompressed_text_dimension)
|
|
from CatalogObjects.ttypes import THdfsCompression
|
|
|
|
|
|
IMPALA_TEST_CLUSTER_PROPERTIES = ImpalaTestClusterProperties.get_instance()
|
|
|
|
|
|
# Tests the COMPUTE STATS command for gathering table and column stats.
|
|
class TestComputeStats(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
super(TestComputeStats, cls).add_test_dimensions()
|
|
cls.ImpalaTestMatrix.add_dimension(create_single_exec_option_dimension())
|
|
# Do not run these tests using all dimensions because the expected results
|
|
# are different for different file formats.
|
|
cls.ImpalaTestMatrix.add_dimension(
|
|
create_uncompressed_text_dimension(cls.get_workload()))
|
|
|
|
@SkipIfLocal.hdfs_blocks
|
|
@SkipIfFS.incorrent_reported_ec
|
|
def test_compute_stats(self, vector, unique_database):
|
|
self.run_test_case('QueryTest/compute-stats', vector, unique_database)
|
|
|
|
@SkipIfLocal.hdfs_blocks
|
|
@SkipIfFS.incorrent_reported_ec
|
|
def test_compute_stats_avro(self, vector, unique_database, cluster_properties):
|
|
if cluster_properties.is_catalog_v2_cluster():
|
|
# IMPALA-7308: changed behaviour of various Avro edge cases significantly in the
|
|
# local catalog - the expected behaviour is different.
|
|
self.run_test_case('QueryTest/compute-stats-avro-catalog-v2', vector,
|
|
unique_database)
|
|
else:
|
|
self.run_test_case('QueryTest/compute-stats-avro', vector, unique_database)
|
|
|
|
@SkipIfLocal.hdfs_blocks
|
|
@SkipIfFS.incorrent_reported_ec
|
|
def test_compute_stats_decimal(self, vector, unique_database):
|
|
# Test compute stats on decimal columns separately so we can vary between platforms
|
|
# with and without write support for decimals (Hive < 0.11 and >= 0.11).
|
|
self.run_test_case('QueryTest/compute-stats-decimal', vector, unique_database)
|
|
|
|
@SkipIfLocal.hdfs_blocks
|
|
@SkipIfFS.incorrent_reported_ec
|
|
def test_compute_stats_date(self, vector, unique_database):
|
|
# Test compute stats on date columns separately.
|
|
self.run_test_case('QueryTest/compute-stats-date', vector, unique_database)
|
|
|
|
@SkipIfFS.incorrent_reported_ec
|
|
def test_compute_stats_incremental(self, vector, unique_database):
|
|
self.run_test_case('QueryTest/compute-stats-incremental', vector, unique_database)
|
|
|
|
def test_compute_stats_complextype_warning(self, vector, unique_database):
|
|
self.run_test_case('QueryTest/compute-stats-complextype-warning', vector,
|
|
unique_database)
|
|
|
|
@pytest.mark.execute_serially
|
|
def test_compute_stats_many_partitions(self, vector):
|
|
# To cut down on test execution time, only run the compute stats test against many
|
|
# partitions if performing an exhaustive test run.
|
|
if self.exploration_strategy() != 'exhaustive': pytest.skip()
|
|
self.run_test_case('QueryTest/compute-stats-many-partitions', vector)
|
|
|
|
@pytest.mark.execute_serially
|
|
def test_compute_stats_keywords(self, vector):
|
|
"""IMPALA-1055: Tests compute stats with a db/table name that are keywords."""
|
|
self.execute_query("drop database if exists `parquet` cascade")
|
|
self.execute_query("create database `parquet`")
|
|
self.execute_query("create table `parquet`.impala_1055 (id INT)")
|
|
self.execute_query("create table `parquet`.`parquet` (id INT)")
|
|
try:
|
|
self.run_test_case('QueryTest/compute-stats-keywords', vector)
|
|
finally:
|
|
self.cleanup_db("parquet", sync_ddl=0)
|
|
|
|
def test_compute_stats_compression_codec(self, unique_database):
|
|
"""IMPALA-8254: Tests that running compute stats with compression_codec set
|
|
should not throw an error."""
|
|
table = "{0}.codec_tbl".format(unique_database)
|
|
self.execute_query_expect_success(self.client, "create table {0}(i int)"
|
|
.format(table))
|
|
for codec in THdfsCompression._NAMES_TO_VALUES.keys():
|
|
for c in [codec.lower(), codec.upper()]:
|
|
self.execute_query_expect_success(self.client, "compute stats {0}".format(table),
|
|
{"compression_codec": c})
|
|
self.execute_query_expect_success(self.client, "drop stats {0}".format(table))
|
|
|
|
@SkipIfFS.hive
|
|
def test_compute_stats_impala_2201(self, unique_database):
|
|
"""IMPALA-2201: Tests that the results of compute incremental stats are properly
|
|
persisted when the data was loaded from Hive with hive.stats.autogather=true.
|
|
"""
|
|
|
|
# Unless something drastic changes in Hive and/or Impala, this test should
|
|
# always succeed.
|
|
if self.exploration_strategy() != 'exhaustive': pytest.skip()
|
|
|
|
# Create a table and load data into a single partition with Hive with
|
|
# stats autogathering.
|
|
table_name = "autogather_test"
|
|
create_load_data_stmts = """
|
|
set hive.stats.autogather=true;
|
|
create table {0}.{1} (c int) partitioned by (p1 int, p2 string);
|
|
insert overwrite table {0}.{1} partition (p1=1, p2="pval")
|
|
select id from functional.alltypestiny;
|
|
""".format(unique_database, table_name)
|
|
self.run_stmt_in_hive(create_load_data_stmts)
|
|
|
|
# Make the table visible in Impala.
|
|
self.execute_query("invalidate metadata %s.%s" % (unique_database, table_name))
|
|
|
|
# Check that the row count was populated during the insert. We expect 8 rows
|
|
# because functional.alltypestiny has 8 rows, but Hive's auto stats gathering
|
|
# is known to be flaky and sometimes sets the row count to 0. So we check that
|
|
# the row count is not -1 instead of checking for 8 directly.
|
|
show_result = \
|
|
self.execute_query("show table stats %s.%s" % (unique_database, table_name))
|
|
assert(len(show_result.data) == 2)
|
|
assert("1\tpval\t-1" not in show_result.data[0])
|
|
|
|
# Compute incremental stats on the single test partition.
|
|
self.execute_query("compute incremental stats %s.%s partition (p1=1, p2='pval')"
|
|
% (unique_database, table_name))
|
|
|
|
# Invalidate metadata to force reloading the stats from the Hive Metastore.
|
|
self.execute_query("invalidate metadata %s.%s" % (unique_database, table_name))
|
|
|
|
# Check that the row count is still 8.
|
|
show_result = \
|
|
self.execute_query("show table stats %s.%s" % (unique_database, table_name))
|
|
assert(len(show_result.data) == 2)
|
|
assert("1\tpval\t8" in show_result.data[0])
|
|
|
|
@staticmethod
|
|
def create_load_test_corrupt_stats(self, unique_database, create_load_stmts,
|
|
table_name, partitions, files):
|
|
"""A helper method for tests against the fix to IMPALA-9744."""
|
|
# Create and load the Hive table.
|
|
self.run_stmt_in_hive(create_load_stmts)
|
|
|
|
# Make the table visible in Impala.
|
|
self.execute_query("invalidate metadata %s.%s" % (unique_database, table_name))
|
|
|
|
# Formulate a simple query that scans the Hive table.
|
|
explain_stmt = """
|
|
explain select * from {0}.{1} where
|
|
int_col > (select 3*stddev(int_col) from {0}.{1})
|
|
""".format(unique_database, table_name)
|
|
explain_result = self.execute_query(explain_stmt)
|
|
|
|
# Formulate a template which verifies the number of partitions and the number
|
|
# of files are per spec.
|
|
hdfs_physical_properties_template \
|
|
= """HDFS partitions={0}/{0} files={1}""".format(partitions, files)
|
|
|
|
# Check that the template formulated above exists and row count of the table is
|
|
# not zero, for all scans.
|
|
for i in range(len(explain_result.data)):
|
|
if ("SCAN HDFS" in explain_result.data[i]):
|
|
assert hdfs_physical_properties_template in explain_result.data[i + 1]
|
|
assert "cardinality=0" not in explain_result.data[i + 2]
|
|
|
|
@SkipIfFS.hive
|
|
def test_corrupted_stats_in_partitioned_hive_tables(self, unique_database):
|
|
"""IMPALA-9744: Tests that the partition stats corruption in Hive tables
|
|
(row count=0, partition size>0, persisted when the data was loaded with
|
|
hive.stats.autogather=true) is handled at the table scan level.
|
|
"""
|
|
# Unless something drastic changes in Hive and/or Impala, this test should
|
|
# always succeed.
|
|
if self.exploration_strategy() != 'exhaustive': pytest.skip()
|
|
|
|
# Load from a local data file
|
|
local_file = os.path.join(os.environ['IMPALA_HOME'],
|
|
"testdata/data/alltypes_tiny_pages.parquet")
|
|
table_name = "partitioned_table_with_corrupted_and_missing_stats"
|
|
|
|
# Setting hive.stats.autogather=true after CRTB DDL but before LOAD DML
|
|
# minimally reproduces the corrupt stats issue.
|
|
create_load_stmts = """
|
|
CREATE TABLE {0}.{1} (
|
|
id int COMMENT 'Add a comment',
|
|
bool_col boolean,
|
|
tinyint_col tinyint,
|
|
smallint_col smallint,
|
|
int_col int,
|
|
bigint_col bigint,
|
|
float_col float,
|
|
double_col double,
|
|
date_string_col string,
|
|
string_col string,
|
|
timestamp_col timestamp,
|
|
year int,
|
|
month int )
|
|
PARTITIONED BY (decade string)
|
|
STORED AS PARQUET;
|
|
set hive.stats.autogather=true;
|
|
load data local inpath '{2}' into table {0}.{1} partition (decade="corrupt-stats");
|
|
set hive.stats.autogather=false;
|
|
load data local inpath '{2}' into table {0}.{1} partition (decade="missing-stats");
|
|
""".format(unique_database, table_name, local_file)
|
|
|
|
self.create_load_test_corrupt_stats(self, unique_database, create_load_stmts,
|
|
table_name, 2, 2)
|
|
|
|
@SkipIfFS.hive
|
|
def test_corrupted_stats_in_unpartitioned_hive_tables(self, unique_database):
|
|
"""IMPALA-9744: Tests that the stats corruption in unpartitioned Hive
|
|
tables (row count=0, partition size>0, persisted when the data was loaded
|
|
with hive.stats.autogather=true) is handled at the table scan level.
|
|
"""
|
|
# Unless something drastic changes in Hive and/or Impala, this test should
|
|
# always succeed.
|
|
if self.exploration_strategy() != 'exhaustive': pytest.skip()
|
|
|
|
# Load from a local data file
|
|
local_file = os.path.join(os.environ['IMPALA_HOME'],
|
|
"testdata/data/alltypes_tiny_pages.parquet")
|
|
table_name = "nonpartitioned_table_with_corrupted_stats"
|
|
|
|
# Setting hive.stats.autogather=true prior to CRTB DDL minimally reproduces the
|
|
# corrupt stats issue.
|
|
create_load_stmts = """
|
|
set hive.stats.autogather=true;
|
|
CREATE TABLE {0}.{1} (
|
|
id int COMMENT 'Add a comment',
|
|
bool_col boolean,
|
|
tinyint_col tinyint,
|
|
smallint_col smallint,
|
|
int_col int,
|
|
bigint_col bigint,
|
|
float_col float,
|
|
double_col double,
|
|
date_string_col string,
|
|
string_col string,
|
|
timestamp_col timestamp,
|
|
year int,
|
|
month int)
|
|
STORED AS PARQUET;
|
|
load data local inpath '{2}' into table {0}.{1};
|
|
""".format(unique_database, table_name, local_file)
|
|
|
|
self.create_load_test_corrupt_stats(self, unique_database, create_load_stmts,
|
|
table_name, 1, 1)
|
|
|
|
@SkipIfCatalogV2.stats_pulling_disabled()
|
|
def test_pull_stats_profile(self, unique_database):
|
|
"""Checks that the frontend profile includes metrics when computing
|
|
incremental statistics.
|
|
"""
|
|
try:
|
|
impalad = ImpalaCluster.get_e2e_test_cluster().impalads[0]
|
|
client = impalad.service.create_hs2_client()
|
|
create = "create table test like functional.alltypes"
|
|
load = "insert into test partition(year, month) select * from functional.alltypes"
|
|
insert = """insert into test partition(year=2009, month=1) values
|
|
(29349999, true, 4, 4, 4, 40,4.400000095367432,40.4,
|
|
"10/21/09","4","2009-10-21 03:24:09.600000000")"""
|
|
stats_all = "compute incremental stats test"
|
|
stats_part = "compute incremental stats test partition (year=2009,month=1)"
|
|
|
|
# Checks that profile does not have metrics for incremental stats when
|
|
# the operation is not 'compute incremental stats'.
|
|
self.execute_query_expect_success(client, "use `%s`" % unique_database)
|
|
profile = self.execute_query_expect_success(client, create).runtime_profile
|
|
assert profile.count("StatsFetch") == 0
|
|
# Checks that incremental stats metrics are present when 'compute incremental
|
|
# stats' is run. Since the table has no stats, expect that no bytes are fetched.
|
|
self.execute_query_expect_success(client, load)
|
|
profile = self.execute_query_expect_success(client, stats_all).runtime_profile
|
|
assert profile.count("StatsFetch") > 1
|
|
assert profile.count("StatsFetch.CompressedBytes: 0") == 1
|
|
# Checks that bytes fetched is non-zero since incremental stats are present now
|
|
# and should have been fetched.
|
|
self.execute_query_expect_success(client, insert)
|
|
profile = self.execute_query_expect_success(client, stats_part).runtime_profile
|
|
assert profile.count("StatsFetch") > 1
|
|
assert profile.count("StatsFetch.CompressedBytes") == 1
|
|
assert profile.count("StatsFetch.CompressedBytes: 0") == 0
|
|
# Adds a partition, computes stats, and checks that the metrics in the profile
|
|
# reflect the operation.
|
|
alter = "alter table test add partition(year=2011, month=1)"
|
|
insert_new_partition = """
|
|
insert into test partition(year=2011, month=1) values
|
|
(29349999, true, 4, 4, 4, 40,4.400000095367432,40.4,
|
|
"10/21/09","4","2009-10-21 03:24:09.600000000")
|
|
"""
|
|
self.execute_query_expect_success(client, alter)
|
|
self.execute_query_expect_success(client, insert_new_partition)
|
|
profile = self.execute_query_expect_success(client, stats_all).runtime_profile
|
|
assert profile.count("StatsFetch.TotalPartitions: 25") == 1
|
|
assert profile.count("StatsFetch.NumPartitionsWithStats: 24") == 1
|
|
finally:
|
|
client.close()
|
|
|
|
|
|
# Tests compute stats on HBase tables. This test is separate from TestComputeStats,
|
|
# because we want to use the existing machanism to disable running tests on hbase/none
|
|
# based on the filesystem type (S3, Isilon, etc.).
|
|
class TestHbaseComputeStats(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
super(TestHbaseComputeStats, cls).add_test_dimensions()
|
|
cls.ImpalaTestMatrix.add_dimension(create_single_exec_option_dimension())
|
|
cls.ImpalaTestMatrix.add_constraint(
|
|
lambda v: v.get_value('table_format').file_format == 'hbase')
|
|
|
|
@pytest.mark.xfail(IMPALA_TEST_CLUSTER_PROPERTIES.is_remote_cluster(),
|
|
reason=("Setting up HBase tests currently assumes a local "
|
|
"mini-cluster. See IMPALA-4661."))
|
|
def test_hbase_compute_stats(self, vector, unique_database):
|
|
self.run_test_case('QueryTest/hbase-compute-stats', vector, unique_database)
|
|
|
|
@pytest.mark.xfail(IMPALA_TEST_CLUSTER_PROPERTIES.is_remote_cluster(),
|
|
reason=("Setting up HBase tests currently assumes a local "
|
|
"mini-cluster. See IMPALA-4661."))
|
|
def test_hbase_compute_stats_incremental(self, vector, unique_database):
|
|
self.run_test_case('QueryTest/hbase-compute-stats-incremental', vector,
|
|
unique_database)
|
|
|
|
|
|
class TestCorruptTableStats(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
super(TestCorruptTableStats, cls).add_test_dimensions()
|
|
cls.ImpalaTestMatrix.add_dimension(create_exec_option_dimension(
|
|
disable_codegen_options=[False], exec_single_node_option=[100]))
|
|
cls.ImpalaTestMatrix.add_dimension(
|
|
create_uncompressed_text_dimension(cls.get_workload()))
|
|
|
|
def test_corrupt_stats(self, vector, unique_database):
|
|
"""IMPALA-1983/IMPALA-1657: Test that in the presence of corrupt table statistics a
|
|
warning is issued and the small query optimization is disabled."""
|
|
if self.exploration_strategy() != 'exhaustive': pytest.skip("Only run in exhaustive")
|
|
self.run_test_case('QueryTest/corrupt-stats', vector, unique_database)
|
|
|
|
|
|
class TestIncompatibleColStats(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
super(TestIncompatibleColStats, cls).add_test_dimensions()
|
|
# There is no reason to run these tests using all dimensions.
|
|
cls.ImpalaTestMatrix.add_dimension(create_single_exec_option_dimension())
|
|
cls.ImpalaTestMatrix.add_dimension(
|
|
create_uncompressed_text_dimension(cls.get_workload()))
|
|
|
|
def test_incompatible_col_stats(self, unique_database):
|
|
"""Tests Impala is able to use tables when the column stats data is not compatible
|
|
with the column type. Regression test for IMPALA-588."""
|
|
|
|
# Create a table with a string column and populate it with some data.
|
|
table_name = unique_database + ".badstats"
|
|
self.client.execute("create table %s (s string)" % table_name)
|
|
self.client.execute("insert into table %s select cast(int_col as string) "
|
|
"from functional.alltypes limit 10" % table_name)
|
|
|
|
# Compute stats for this table, they will be for the string column type.
|
|
self.client.execute("compute stats %s" % table_name)
|
|
|
|
# Change the column type to int which will cause a mismatch between the column
|
|
# stats data and the column type metadata.
|
|
self.client.execute("alter table %s change s s int" % table_name)
|
|
# Force a reload of the table metadata.
|
|
self.client.execute("invalidate metadata %s" % table_name)
|
|
# Should still be able to load the metadata and query the table.
|
|
result = self.client.execute("select s from %s" % table_name)
|
|
assert len(result.data) == 10
|
|
|
|
# Recompute stats with the new column type. Impala should now have stats for this
|
|
# column and should be able to access the table.
|
|
# TODO: Currently this just verifies Impala can query the table, it does not
|
|
# verify the stats are there or correct. Expand the verification once Impala has a
|
|
# mechanism to expose this metadata.
|
|
self.client.execute("compute stats %s" % table_name)
|
|
result = self.client.execute("select s from %s" % table_name)
|
|
assert len(result.data) == 10
|
|
|
|
|
|
# Test column min/max stats currently enabled for Parquet tables.
|
|
class TestParquetComputeColumnMinMax(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
super(TestParquetComputeColumnMinMax, cls).add_test_dimensions()
|
|
cls.ImpalaTestMatrix.add_dimension(create_single_exec_option_dimension())
|
|
cls.ImpalaTestMatrix.add_constraint(
|
|
lambda v: v.get_value('table_format').file_format == 'parquet')
|
|
|
|
def test_compute_stats(self, vector, unique_database):
|
|
self.run_test_case('QueryTest/compute-stats-column-minmax', vector, unique_database)
|
|
|
|
|
|
class TestInvalidStatsFromHms(ImpalaTestSuite):
|
|
@classmethod
|
|
def add_test_dimensions(cls):
|
|
super(TestInvalidStatsFromHms, cls).add_test_dimensions()
|
|
cls.ImpalaTestMatrix.add_dimension(create_single_exec_option_dimension())
|
|
cls.ImpalaTestMatrix.add_constraint(
|
|
lambda v: v.get_value('table_format').file_format == 'text'
|
|
and v.get_value('table_format').compression_codec == 'none')
|
|
|
|
def test_invalid_col_stats(self, unique_database):
|
|
"""Test that invalid column stats, i.e. values < -1, are normalized in Impala"""
|
|
tbl = unique_database + ".tbl"
|
|
self.execute_query("create table {} as select 1 as id, 'aaa' as name".format(tbl))
|
|
# Add invalid stats in HMS
|
|
hms_client, _ = ImpalaTestSuite.create_hive_client(9083)
|
|
cs = ColumnStatistics()
|
|
cs.engine = "impala"
|
|
isTblLevel = True
|
|
cs.statsDesc = ColumnStatisticsDesc(isTblLevel, unique_database, "tbl")
|
|
cs_data = ColumnStatisticsData()
|
|
maxColLen = -100
|
|
avgColLen = -200
|
|
numNulls = -300
|
|
numDVs = -400
|
|
cs_data.stringStats = StringColumnStatsData(maxColLen, avgColLen, numNulls, numDVs)
|
|
cs_obj = ColumnStatisticsObj("name", "string", cs_data)
|
|
cs.statsObj = [cs_obj]
|
|
assert hms_client.update_table_column_statistics(cs)
|
|
# REFRESH to reload the stats
|
|
self.execute_query("refresh " + tbl)
|
|
# Verify the invalid stats are normalized to -1
|
|
res = self.execute_query("show column stats " + tbl)
|
|
assert res.data == [
|
|
'id\tTINYINT\t-1\t-1\t1\t1\t-1\t-1',
|
|
'name\tSTRING\t-1\t-1\t-1\t-1\t-1\t-1']
|