2023-02-23 18:03:45 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import requests
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
|
|
|
|
CURDIR = os.path.dirname(os.path.realpath(__file__))
|
2023-03-23 15:33:23 +00:00
|
|
|
sys.path.insert(0, os.path.join(CURDIR, "helpers"))
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
from pure_http_client import ClickHouseClient
|
|
|
|
|
|
|
|
|
|
|
|
class Tester:
|
2023-03-23 15:33:23 +00:00
|
|
|
"""
|
2023-02-23 18:03:45 +00:00
|
|
|
- Creates test table with multiple integer columns
|
|
|
|
- Runs read queries with multiple range conditions on different columns in PREWHERE and check that the result is correct
|
2023-03-23 15:33:23 +00:00
|
|
|
"""
|
|
|
|
|
2023-02-23 18:03:45 +00:00
|
|
|
def __init__(self, session, url, index_granularity, total_rows):
|
|
|
|
self.session = session
|
|
|
|
self.url = url
|
|
|
|
self.index_granularity = index_granularity
|
|
|
|
self.total_rows = total_rows
|
|
|
|
self.reported_errors = set()
|
|
|
|
self.repro_queries = []
|
|
|
|
|
|
|
|
def report_error(self):
|
2023-03-23 15:33:23 +00:00
|
|
|
print("Repro steps:", "\n\n\t".join(self.repro_queries))
|
2023-02-23 18:03:45 +00:00
|
|
|
exit(1)
|
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
def query(self, query_text, include_in_repro_steps=True, expected_data=None):
|
2023-02-23 18:03:45 +00:00
|
|
|
self.repro_queries.append(query_text)
|
|
|
|
resp = self.session.post(self.url, data=query_text)
|
|
|
|
if resp.status_code != 200:
|
|
|
|
# Group similar errors
|
|
|
|
error = resp.text[0:40]
|
|
|
|
if error not in self.reported_errors:
|
|
|
|
self.reported_errors.add(error)
|
2023-03-23 15:33:23 +00:00
|
|
|
print("Code:", resp.status_code)
|
|
|
|
print("Result:", resp.text)
|
2023-02-23 18:03:45 +00:00
|
|
|
self.report_error()
|
|
|
|
|
|
|
|
result = resp.text
|
|
|
|
# Check that the result is as expected
|
2023-03-23 15:33:23 +00:00
|
|
|
if (not expected_data is None) and (int(result) != len(expected_data)):
|
|
|
|
print("Expected {} rows, got {}".format(len(expected_data), result))
|
|
|
|
print("Expected data:" + str(expected_data))
|
2023-02-23 18:03:45 +00:00
|
|
|
self.report_error()
|
|
|
|
|
|
|
|
if not include_in_repro_steps:
|
|
|
|
self.repro_queries.pop()
|
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
def check_data(
|
|
|
|
self, all_data, c_range_start, c_range_end, d_range_start, d_range_end
|
|
|
|
):
|
|
|
|
for to_select in [
|
|
|
|
"count()",
|
|
|
|
"sum(e)",
|
|
|
|
]: # Test reading with and without column with default value
|
|
|
|
self.query("SELECT {} FROM tab_02473;".format(to_select), False, all_data)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
delta = 10
|
|
|
|
for b_range_start in [0, delta]:
|
2023-03-23 15:33:23 +00:00
|
|
|
for b_range_end in [self.total_rows - delta]: # , self.total_rows]:
|
2023-02-23 18:03:45 +00:00
|
|
|
expected = all_data[
|
2023-03-23 15:33:23 +00:00
|
|
|
(all_data.a == 0)
|
|
|
|
& (all_data.b > b_range_start)
|
|
|
|
& (all_data.b <= b_range_end)
|
|
|
|
]
|
|
|
|
self.query(
|
|
|
|
"SELECT {} from tab_02473 PREWHERE b > {} AND b <= {} WHERE a == 0;".format(
|
|
|
|
to_select, b_range_start, b_range_end
|
|
|
|
),
|
|
|
|
False,
|
|
|
|
expected,
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
expected = all_data[
|
2023-03-23 15:33:23 +00:00
|
|
|
(all_data.a == 0)
|
|
|
|
& (all_data.b > b_range_start)
|
|
|
|
& (all_data.b <= b_range_end)
|
|
|
|
& (all_data.c > c_range_start)
|
|
|
|
& (all_data.c <= c_range_end)
|
|
|
|
]
|
|
|
|
self.query(
|
|
|
|
"SELECT {} from tab_02473 PREWHERE b > {} AND b <= {} AND c > {} AND c <= {} WHERE a == 0;".format(
|
|
|
|
to_select,
|
|
|
|
b_range_start,
|
|
|
|
b_range_end,
|
|
|
|
c_range_start,
|
|
|
|
c_range_end,
|
|
|
|
),
|
|
|
|
False,
|
|
|
|
expected,
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
expected = all_data[
|
2023-03-23 15:33:23 +00:00
|
|
|
(all_data.a == 0)
|
|
|
|
& (all_data.b > b_range_start)
|
|
|
|
& (all_data.b <= b_range_end)
|
|
|
|
& (all_data.c > c_range_start)
|
|
|
|
& (all_data.c <= c_range_end)
|
|
|
|
& (all_data.d > d_range_start)
|
|
|
|
& (all_data.d <= d_range_end)
|
|
|
|
]
|
|
|
|
self.query(
|
|
|
|
"SELECT {} from tab_02473 PREWHERE b > {} AND b <= {} AND c > {} AND c <= {} AND d > {} AND d <= {} WHERE a == 0;".format(
|
|
|
|
to_select,
|
|
|
|
b_range_start,
|
|
|
|
b_range_end,
|
|
|
|
c_range_start,
|
|
|
|
c_range_end,
|
|
|
|
d_range_start,
|
|
|
|
d_range_end,
|
|
|
|
),
|
|
|
|
False,
|
|
|
|
expected,
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
def run_test(self, c_range_start, c_range_end, d_range_start, d_range_end):
|
|
|
|
self.repro_queries = []
|
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
self.query(
|
|
|
|
"""
|
2023-02-23 18:03:45 +00:00
|
|
|
CREATE TABLE tab_02473 (a Int8, b Int32, c Int32, d Int32, PRIMARY KEY (a))
|
|
|
|
ENGINE = MergeTree() ORDER BY (a, b)
|
2023-03-23 15:33:23 +00:00
|
|
|
SETTINGS min_bytes_for_wide_part = 0, index_granularity = {};""".format(
|
|
|
|
self.index_granularity
|
|
|
|
)
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
self.query(
|
|
|
|
"INSERT INTO tab_02473 select 0, number+1, number+1, number+1 FROM numbers({});".format(
|
|
|
|
self.total_rows
|
|
|
|
)
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
client = ClickHouseClient()
|
2023-03-23 15:33:23 +00:00
|
|
|
all_data = client.query_return_df(
|
|
|
|
"SELECT a, b, c, d, 1 as e FROM tab_02473 FORMAT TabSeparatedWithNames;"
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
self.query("OPTIMIZE TABLE tab_02473 FINAL SETTINGS mutations_sync=2;")
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
# After all data has been written add a column with default value
|
2023-03-23 15:33:23 +00:00
|
|
|
self.query("ALTER TABLE tab_02473 ADD COLUMN e Int64 DEFAULT 1;")
|
2023-02-23 18:03:45 +00:00
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
self.check_data(
|
|
|
|
all_data, c_range_start, c_range_end, d_range_start, d_range_end
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
self.query("DROP TABLE tab_02473;")
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
# Enable multiple prewhere read steps
|
2023-03-23 15:33:23 +00:00
|
|
|
url = (
|
|
|
|
os.environ["CLICKHOUSE_URL"]
|
|
|
|
+ "&enable_multiple_prewhere_read_steps=1&move_all_conditions_to_prewhere=0&max_threads=1"
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
2023-03-23 15:33:23 +00:00
|
|
|
default_index_granularity = 10
|
2023-02-23 18:03:45 +00:00
|
|
|
total_rows = 8 * default_index_granularity
|
|
|
|
step = default_index_granularity
|
|
|
|
session = requests.Session()
|
2023-03-23 15:33:23 +00:00
|
|
|
for index_granularity in [default_index_granularity - 1, default_index_granularity]:
|
2023-02-23 18:03:45 +00:00
|
|
|
tester = Tester(session, url, index_granularity, total_rows)
|
|
|
|
# Test combinations of ranges of columns c and d
|
|
|
|
for c_range_start in range(0, total_rows, int(2.3 * step)):
|
2023-03-23 15:33:23 +00:00
|
|
|
for c_range_end in range(
|
|
|
|
c_range_start + 3 * step, total_rows, int(2.1 * step)
|
|
|
|
):
|
|
|
|
for d_range_start in range(
|
|
|
|
int(0.5 * step), total_rows, int(2.7 * step)
|
|
|
|
):
|
|
|
|
for d_range_end in range(
|
|
|
|
d_range_start + 3 * step, total_rows, int(2.2 * step)
|
|
|
|
):
|
|
|
|
tester.run_test(
|
|
|
|
c_range_start, c_range_end, d_range_start, d_range_end
|
|
|
|
)
|
2023-02-23 18:03:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|