From 5ab0e7779dbc31b5e0a9196833cafc463158d599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B5=D1=80=D1=88=D0=B8=D0=BD=D0=B8=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=9E=D0=BB=D1=8C=D0=B3=D0=B0=20=D0=90=D1=80=D1=82=D0=B5=D0=BC?= =?UTF-8?q?=D0=BE=D0=B2=D0=BD=D0=B0?= <79264258+olyannaa@users.noreply.github.com> Date: Tue, 30 Jun 2026 16:45:35 +0500 Subject: [PATCH] Revert "Feat/rule cards batch" --- clickadvisor/ml/__init__.py | 3 - clickadvisor/ml/dataset.py | 81 ---- clickadvisor/ml/features.py | 429 ------------------ .../detectors/D015_optimize_table_final.py | 46 -- .../detectors/D016_alter_table_mutation.py | 49 -- .../detectors/D017_nullable_column_in_ddl.py | 54 --- .../D018_deprecated_ngrambf_tokenbf_index.py | 51 --- .../D019_set_zero_unlimited_skip_index.py | 48 -- .../rules/tier1/R021_datetime64_zero.py | 51 --- .../rules/tier1/R022_float_monetary.py | 62 --- .../tier1/R023_string_datetime_column.py | 67 --- .../rules/tier1/R024_string_ip_column.py | 75 --- .../rules/tier1/R025_order_by_tuple.py | 57 --- .../rules/tier1/R026_sum_case_to_countif.py | 44 -- .../rules/tier1/R027_sum_case_col_to_sumif.py | 46 -- .../rules/tier1/R028_coalesce_to_ifnull.py | 45 -- .../rules/tier1/R029_lower_like_to_ilike.py | 46 -- .../rules/tier1/R030_not_in_singleton.py | 45 -- .../rules/tier1/R031_string_uuid_column.py | 67 --- data/ml/features_dataset.jsonl | 162 ------- .../cards/D-015-optimize_table_final.yaml | 40 -- .../cards/D-016-alter_table_mutation.yaml | 41 -- .../cards/D-017-nullable_column_in_ddl.yaml | 42 -- ...-018-deprecated_ngrambf_tokenbf_index.yaml | 38 -- .../D-019-set_zero_unlimited_skip_index.yaml | 40 -- .../cards/E-012-join_use_nulls_overhead.yaml | 46 -- ...-013-async_insert_busy_timeout_tuning.yaml | 47 -- .../E-014-merge_max_bytes_for_level.yaml | 47 -- .../R-021-datetime64_zero_to_datetime.yaml | 43 -- ...-022-float_monetary_column_to_decimal.yaml | 45 -- .../R-023-string_datetime_column_to_date.yaml | 43 -- .../cards/R-024-string_ip_column_to_ipv4.yaml | 42 -- .../cards/R-025-order_by_tuple_no_pk.yaml | 42 -- .../cards/R-026-sum_case_to_countif.yaml | 35 -- .../cards/R-027-sum_case_col_to_sumif.yaml | 36 -- .../R-028-coalesce_two_args_to_ifnull.yaml | 32 -- .../cards/R-029-lower_col_like_to_ilike.yaml | 36 -- .../R-030-not_in_singleton_to_not_equal.yaml | 35 -- ...R-031-string_uuid_column_to_uuid_type.yaml | 42 -- .../R-032-int8_boolean_column_to_bool.yaml | 42 -- scripts/ml/__init__.py | 0 scripts/ml/extract_dataset_features.py | 107 ----- tests/ml/__init__.py | 0 tests/ml/test_features.py | 339 -------------- 44 files changed, 2788 deletions(-) delete mode 100644 clickadvisor/ml/__init__.py delete mode 100644 clickadvisor/ml/dataset.py delete mode 100644 clickadvisor/ml/features.py delete mode 100644 clickadvisor/rules/detectors/D015_optimize_table_final.py delete mode 100644 clickadvisor/rules/detectors/D016_alter_table_mutation.py delete mode 100644 clickadvisor/rules/detectors/D017_nullable_column_in_ddl.py delete mode 100644 clickadvisor/rules/detectors/D018_deprecated_ngrambf_tokenbf_index.py delete mode 100644 clickadvisor/rules/detectors/D019_set_zero_unlimited_skip_index.py delete mode 100644 clickadvisor/rules/tier1/R021_datetime64_zero.py delete mode 100644 clickadvisor/rules/tier1/R022_float_monetary.py delete mode 100644 clickadvisor/rules/tier1/R023_string_datetime_column.py delete mode 100644 clickadvisor/rules/tier1/R024_string_ip_column.py delete mode 100644 clickadvisor/rules/tier1/R025_order_by_tuple.py delete mode 100644 clickadvisor/rules/tier1/R026_sum_case_to_countif.py delete mode 100644 clickadvisor/rules/tier1/R027_sum_case_col_to_sumif.py delete mode 100644 clickadvisor/rules/tier1/R028_coalesce_to_ifnull.py delete mode 100644 clickadvisor/rules/tier1/R029_lower_like_to_ilike.py delete mode 100644 clickadvisor/rules/tier1/R030_not_in_singleton.py delete mode 100644 clickadvisor/rules/tier1/R031_string_uuid_column.py delete mode 100644 data/ml/features_dataset.jsonl delete mode 100644 docs/rules/cards/D-015-optimize_table_final.yaml delete mode 100644 docs/rules/cards/D-016-alter_table_mutation.yaml delete mode 100644 docs/rules/cards/D-017-nullable_column_in_ddl.yaml delete mode 100644 docs/rules/cards/D-018-deprecated_ngrambf_tokenbf_index.yaml delete mode 100644 docs/rules/cards/D-019-set_zero_unlimited_skip_index.yaml delete mode 100644 docs/rules/cards/E-012-join_use_nulls_overhead.yaml delete mode 100644 docs/rules/cards/E-013-async_insert_busy_timeout_tuning.yaml delete mode 100644 docs/rules/cards/E-014-merge_max_bytes_for_level.yaml delete mode 100644 docs/rules/cards/R-021-datetime64_zero_to_datetime.yaml delete mode 100644 docs/rules/cards/R-022-float_monetary_column_to_decimal.yaml delete mode 100644 docs/rules/cards/R-023-string_datetime_column_to_date.yaml delete mode 100644 docs/rules/cards/R-024-string_ip_column_to_ipv4.yaml delete mode 100644 docs/rules/cards/R-025-order_by_tuple_no_pk.yaml delete mode 100644 docs/rules/cards/R-026-sum_case_to_countif.yaml delete mode 100644 docs/rules/cards/R-027-sum_case_col_to_sumif.yaml delete mode 100644 docs/rules/cards/R-028-coalesce_two_args_to_ifnull.yaml delete mode 100644 docs/rules/cards/R-029-lower_col_like_to_ilike.yaml delete mode 100644 docs/rules/cards/R-030-not_in_singleton_to_not_equal.yaml delete mode 100644 docs/rules/cards/R-031-string_uuid_column_to_uuid_type.yaml delete mode 100644 docs/rules/cards/R-032-int8_boolean_column_to_bool.yaml delete mode 100644 scripts/ml/__init__.py delete mode 100644 scripts/ml/extract_dataset_features.py delete mode 100644 tests/ml/__init__.py delete mode 100644 tests/ml/test_features.py diff --git a/clickadvisor/ml/__init__.py b/clickadvisor/ml/__init__.py deleted file mode 100644 index 2e864413..00000000 --- a/clickadvisor/ml/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Feature extraction and classification utilities for ClickAdvisor's ML -evaluation surface. Independent from the deterministic rule engine in -clickadvisor/rules/.""" diff --git a/clickadvisor/ml/dataset.py b/clickadvisor/ml/dataset.py deleted file mode 100644 index 30d9b589..00000000 --- a/clickadvisor/ml/dataset.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterable -from dataclasses import dataclass -from pathlib import Path -from typing import Any - -import yaml - -from clickadvisor.ml.features import FeatureMap, QueryFeatureExtractor - - -@dataclass(frozen=True, slots=True) -class BenchmarkExample: - case_id: str - sql: str - labels: tuple[str, ...] - features: FeatureMap - - -def load_benchmark_cases(cases_dir: Path) -> list[dict[str, Any]]: - cases: list[dict[str, Any]] = [] - for path in sorted(cases_dir.glob("*.yaml")): - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - if isinstance(payload, dict): - cases.append(payload) - return cases - - -def load_split(split_path: Path) -> dict[str, set[str]]: - payload = yaml.safe_load(split_path.read_text(encoding="utf-8")) - if not isinstance(payload, dict): - raise ValueError("split metadata must be a YAML object") - return { - "train": set(_as_string_list(payload.get("train_case_ids"), "train_case_ids")), - "test": set(_as_string_list(payload.get("test_case_ids"), "test_case_ids")), - } - - -def build_examples( - cases: Iterable[dict[str, Any]], - extractor: QueryFeatureExtractor | None = None, -) -> list[BenchmarkExample]: - feature_extractor = extractor or QueryFeatureExtractor() - examples: list[BenchmarkExample] = [] - for case in cases: - case_id = _required_string(case, "case_id") - sql = _required_string(case, "sql") - labels = tuple(_as_string_list(case.get("expected_rules_to_fire"), "expected_rules_to_fire")) - features = feature_extractor.extract(sql).features - examples.append(BenchmarkExample(case_id=case_id, sql=sql, labels=labels, features=features)) - return examples - - -def split_examples( - examples: Iterable[BenchmarkExample], - split: dict[str, set[str]], -) -> tuple[list[BenchmarkExample], list[BenchmarkExample]]: - train_ids = split["train"] - test_ids = split["test"] - train: list[BenchmarkExample] = [] - test: list[BenchmarkExample] = [] - for example in examples: - if example.case_id in train_ids: - train.append(example) - elif example.case_id in test_ids: - test.append(example) - return train, test - - -def _required_string(payload: dict[str, Any], key: str) -> str: - value = payload.get(key) - if not isinstance(value, str) or not value: - raise ValueError(f"{key} must be a non-empty string") - return value - - -def _as_string_list(value: Any, key: str) -> list[str]: - if not isinstance(value, list) or not all(isinstance(item, str) for item in value): - raise ValueError(f"{key} must be a list of strings") - return value diff --git a/clickadvisor/ml/features.py b/clickadvisor/ml/features.py deleted file mode 100644 index 5af76bb1..00000000 --- a/clickadvisor/ml/features.py +++ /dev/null @@ -1,429 +0,0 @@ -from __future__ import annotations - -import logging -import re -from collections.abc import Mapping -from dataclasses import asdict, dataclass - -import sqlglot -import sqlglot.expressions as exp - -from clickadvisor.core.sql_parser import SQLParser - -FeatureMap = dict[str, float] - -_ASYNC_INSERT_RE = re.compile(r"\basync_insert\s*=\s*1\b", re.IGNORECASE) -_WAIT_FLAG_RE = re.compile(r"\bwait_for_async_insert\s*=\s*1\b", re.IGNORECASE) -_INSERT_RE = re.compile(r"\bINSERT\b", re.IGNORECASE) -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_UINT64_COL_RE = re.compile(r"`?(\w+)`?\s+(?:UInt64|Int64)\b", re.IGNORECASE) -_LOW_CARDINALITY_PARTS = frozenset( - ["type", "status", "category", "flag", "level", "kind", "state", "mode", "priority", "rank", "class"] -) -_TO_TYPE_PREFIXES = ( - "touint", "toint", "tofloat", "tostring", "todecimal", - "todate", "todatetime", "tofixedstring", "touuid", -) -_OR_SAFE_SUFFIXES = ("orzero", "ornull", "ordefault") - - -@dataclass(slots=True) -class QueryFeatures: - """Structured AST/text feature vector for a single SQL query. - - Boolean fields map 1-to-1 to patterns from the deterministic rule engine - but are computed independently so the classifier can generalise beyond - exact rule boundaries. - """ - - # --- count / distinct --- - has_count_distinct: bool - # --- projection --- - has_select_star: bool - # --- table modifiers --- - has_final_modifier: bool - # --- set operators --- - has_union: bool - has_union_all: bool - # --- grouping --- - has_group_by: bool - has_group_by_string_column: bool - # --- having --- - has_having: bool - has_having_without_aggregate: bool - # --- filter functions --- - has_function_on_filter_column: bool - # --- subquery --- - has_subquery: bool - has_subquery_with_orderby_no_limit: bool - has_nested_subquery_filter: bool - # --- predicate patterns --- - has_or_chain_same_column: bool - has_in_with_single_value: bool - # --- quantile --- - has_quantile_exact: bool - # --- cast --- - has_cast: bool - has_cast_without_default: bool - # --- async insert --- - has_async_insert_setting: bool - has_async_insert_without_wait: bool - # --- limit --- - has_limit: bool - has_no_limit: bool - # --- misc predicates --- - has_constant_predicate: bool - has_length_zero_check: bool - # --- numeric shape features --- - table_count: int - column_count_in_select: int - where_clause_depth: int - query_length_chars: int - - def to_vector(self) -> dict[str, float | int]: - """Convert to numeric dict for model input. Bools become 0/1.""" - result: dict[str, float | int] = {} - for field, value in asdict(self).items(): - result[field] = int(value) if isinstance(value, bool) else value - return result - - -def _node_depth(node: exp.Expression) -> int: - """Recursively compute maximum AST depth below *node*.""" - children: list[exp.Expression] = [] - for val in node.args.values(): - if isinstance(val, exp.Expression): - children.append(val) - elif isinstance(val, list): - children.extend(c for c in val if isinstance(c, exp.Expression)) - if not children: - return 0 - return 1 + max(_node_depth(c) for c in children) - - -def _where_depth(ast: sqlglot.Expression) -> int: - max_depth = 0 - for where in ast.find_all(exp.Where): - max_depth = max(max_depth, _node_depth(where.this)) - return max_depth - - -def _has_cast_without_default(ast: sqlglot.Expression) -> bool: - """True when a throwing CAST (no OrDefault/OrZero/OrNull) is present.""" - for cast in ast.find_all(exp.Cast): - if isinstance(cast.this, exp.Column): - return True - for fn in ast.find_all(exp.Anonymous): - name = fn.name.lower() - if name.endswith(_OR_SAFE_SUFFIXES): - continue - if name.startswith(_TO_TYPE_PREFIXES): - if fn.expressions and isinstance(fn.expressions[0], exp.Column): - return True - return False - - -def _has_cast(ast: sqlglot.Expression) -> bool: - """True when any cast or type-conversion function is present.""" - if any(True for _ in ast.find_all(exp.Cast)): - return True - for fn in ast.find_all(exp.Anonymous): - if fn.name.lower().startswith(_TO_TYPE_PREFIXES): - return True - return False - - -def _has_async_insert_without_wait(sql: str) -> bool: - return bool( - _INSERT_RE.search(sql) - and _ASYNC_INSERT_RE.search(sql) - and not _WAIT_FLAG_RE.search(sql) - ) - - -def _has_oversized_uint_candidate(sql: str) -> bool: - if not _CREATE_TABLE_RE.search(sql): - return False - for match in _UINT64_COL_RE.finditer(sql): - col = match.group(1).lower() - parts = col.split("_") - if _LOW_CARDINALITY_PARTS.intersection(parts): - return True - return False - - -class FeatureExtractor: - """Extract QueryFeatures from raw SQL via sqlglot AST with regex fallback.""" - - def __init__(self) -> None: - self._parser = SQLParser() - - def extract(self, sql: str) -> QueryFeatures: - """Parse *sql* via sqlglot (clickhouse dialect) and extract all features. - - If sqlglot raises ParseError the regex fallback path is used and a - warning is logged. The returned QueryFeatures will have False/0 for any - field that cannot be derived from text alone. - """ - try: - ast = self._parser.parse(sql) - except sqlglot.errors.ParseError: - logging.warning( - "AST parse failed for SQL (len=%d), using regex fallback", - len(sql), - ) - return self._regex_fallback(sql) - return self._from_ast(ast, sql) - - def _from_ast(self, ast: sqlglot.Expression, sql: str) -> QueryFeatures: - p = self._parser - top = ast if isinstance(ast, exp.Select) else None - - has_union = any(True for _ in ast.find_all(exp.Union)) - has_union_all = any( - u.args.get("distinct") is False for u in ast.find_all(exp.Union) - ) - has_having = any(True for _ in ast.find_all(exp.Having)) - has_subquery = any(True for _ in ast.find_all(exp.Subquery)) - has_limit = any(True for _ in ast.find_all(exp.Limit)) - # GROUP BY anywhere in the query tree (including subqueries) - has_group_by = any( - s.args.get("group") is not None for s in ast.find_all(exp.Select) - ) - - col_count = len(top.expressions) if top is not None else 0 - t_count = sum(1 for _ in ast.find_all(exp.Table)) - - return QueryFeatures( - has_count_distinct=p.has_count_distinct(ast), - has_select_star=p.has_top_level_select_star(ast), - has_final_modifier=p.has_final_modifier(ast), - has_union=has_union, - has_union_all=has_union_all, - has_group_by=has_group_by, - has_group_by_string_column=p.has_groupby_string_candidate(ast), - has_having=has_having, - has_having_without_aggregate=p.has_having_without_agg(ast), - has_function_on_filter_column=( - p.has_todate_equality(ast) - or p.has_date_part_equality(ast) - or p.has_interval_start_equality(ast) - or p.has_redundant_cast(ast) - ), - has_subquery=has_subquery, - has_subquery_with_orderby_no_limit=p.has_orderby_without_limit_in_subquery(ast), - has_nested_subquery_filter=p.has_subquery_filter_pushdown(ast), - has_or_chain_same_column=p.has_disjunction_chain(ast), - has_in_with_single_value=p.has_in_singleton(ast), - has_quantile_exact=p.has_quantile_exact(ast), - has_cast=_has_cast(ast), - has_cast_without_default=_has_cast_without_default(ast), - has_async_insert_setting=bool(_ASYNC_INSERT_RE.search(sql)), - has_async_insert_without_wait=_has_async_insert_without_wait(sql), - has_limit=has_limit, - has_no_limit=p.has_missing_limit(ast), - has_constant_predicate=p.has_constant_predicate(ast), - has_length_zero_check=p.has_length_empty_pattern(ast), - table_count=t_count, - column_count_in_select=col_count, - where_clause_depth=_where_depth(ast), - query_length_chars=len(sql), - ) - - def _regex_fallback(self, sql: str) -> QueryFeatures: - s_upper = sql.upper() - has_union = bool(re.search(r"\bUNION\b", sql, re.I)) - has_union_all = bool(re.search(r"\bUNION\s+ALL\b", sql, re.I)) - has_limit = bool(re.search(r"\bLIMIT\b", sql, re.I)) - has_cast = bool( - re.search(r"\bCAST\s*\(", sql, re.I) - or any(re.search(rf"\b{p}", sql, re.I) for p in _TO_TYPE_PREFIXES) - ) - return QueryFeatures( - has_count_distinct=bool(re.search(r"COUNT\s*\(\s*DISTINCT", sql, re.I)), - has_select_star=bool(re.search(r"\bSELECT\s+\*", sql, re.I)), - has_final_modifier=bool(re.search(r"\bFINAL\b", sql, re.I)), - has_union=has_union, - has_union_all=has_union_all, - has_group_by=bool(re.search(r"\bGROUP\s+BY\b", sql, re.I)), - has_group_by_string_column=False, - has_having=bool(re.search(r"\bHAVING\b", sql, re.I)), - has_having_without_aggregate=False, - has_function_on_filter_column=bool( - re.search(r"\btoDate\s*\(|\btoYYYYMM\s*\(|\btoStartOf", sql, re.I) - ), - has_subquery=bool(re.search(r"\bSELECT\b.*\bSELECT\b", sql, re.I | re.DOTALL)), - has_subquery_with_orderby_no_limit=False, - has_nested_subquery_filter=False, - has_or_chain_same_column=False, - has_in_with_single_value=bool(re.search(r"\bIN\s*\(\s*'[^']*'\s*\)", sql, re.I)), - has_quantile_exact=bool(re.search(r"\bquantileExact\b", sql, re.I)), - has_cast=has_cast, - has_cast_without_default=has_cast, - has_async_insert_setting=bool(_ASYNC_INSERT_RE.search(sql)), - has_async_insert_without_wait=_has_async_insert_without_wait(sql), - has_limit=has_limit, - has_no_limit=False, - has_constant_predicate=bool( - re.search(r"\bWHERE\b.*\bTRUE\b", sql, re.I | re.DOTALL) - or re.search(r"\b1\s*=\s*1\b", sql, re.I) - ), - has_length_zero_check=bool(re.search(r"\blength\s*\(", sql, re.I)), - table_count=0, - column_count_in_select=0, - where_clause_depth=0, - query_length_chars=len(sql), - ) - - -# --------------------------------------------------------------------------- -# Legacy classes — kept for backward compatibility with clickadvisor/ml/dataset.py -# --------------------------------------------------------------------------- - - -@dataclass(frozen=True, slots=True) -class FeatureVector: - sql: str - features: FeatureMap - - -class QueryFeatureExtractor: - """Extract deterministic AST/text features for classical ML baselines.""" - - def __init__(self) -> None: - self.parser = SQLParser() - - def extract(self, sql: str) -> FeatureVector: - features = self._base_text_features(sql) - try: - ast = self.parser.parse(sql) - except sqlglot.errors.ParseError: - features["parse_error"] = 1.0 - features.update(self._regex_features(sql)) - return FeatureVector(sql=sql, features=features) - - features["parse_error"] = 0.0 - features.update(self._ast_shape_features(ast)) - features.update(self._rule_pattern_features(ast, sql)) - return FeatureVector(sql=sql, features=features) - - def _base_text_features(self, sql: str) -> FeatureMap: - normalized = sql.strip() - return { - "sql_length_chars": float(len(normalized)), - "sql_line_count": float(max(1, normalized.count("\n") + 1)), - "contains_comment": float("--" in normalized or "/*" in normalized), - "contains_settings_clause": float(bool(re.search(r"\bsettings\b", normalized, re.I))), - } - - def _ast_shape_features(self, ast: sqlglot.Expression) -> FeatureMap: - top_level_select = isinstance(ast, exp.Select) - group = ast.args.get("group") if top_level_select else None - return { - "is_select": float(top_level_select), - "is_insert": float(isinstance(ast, exp.Insert)), - "is_create": float(isinstance(ast, exp.Create)), - "select_count": float(sum(1 for _ in ast.find_all(exp.Select))), - "table_count": float(sum(1 for _ in ast.find_all(exp.Table))), - "join_count": float(sum(1 for _ in ast.find_all(exp.Join))), - "subquery_count": float(sum(1 for _ in ast.find_all(exp.Subquery))), - "where_count": float(sum(1 for _ in ast.find_all(exp.Where))), - "having_count": float(sum(1 for _ in ast.find_all(exp.Having))), - "order_count": float(sum(1 for _ in ast.find_all(exp.Order))), - "limit_count": float(sum(1 for _ in ast.find_all(exp.Limit))), - "groupby_key_count": float(len(group.expressions) if isinstance(group, exp.Group) else 0), - "function_call_count": float(self._function_call_count(ast)), - "aggregate_call_count": float(self._aggregate_call_count(ast)), - "literal_count": float(sum(1 for _ in ast.find_all(exp.Literal))), - } - - def _rule_pattern_features(self, ast: sqlglot.Expression, sql: str) -> FeatureMap: - return { - "has_count_distinct": float(self.parser.has_count_distinct(ast)), - "has_quantile_exact": float(self.parser.has_quantile_exact(ast)), - "has_count_star_distinct_subquery": float( - self.parser.has_count_star_distinct_subquery(ast) - ), - "has_todate_equality": float(self.parser.has_todate_equality(ast)), - "has_date_part_equality": float(self.parser.has_date_part_equality(ast)), - "has_interval_start_equality": float(self.parser.has_interval_start_equality(ast)), - "has_function_on_filter_column": float(self._has_function_on_filter_column(ast)), - "has_redundant_cast": float(self.parser.has_redundant_cast(ast)), - "has_singleton_in": float(self.parser.has_in_singleton(ast)), - "has_disjunction_chain": float(self.parser.has_disjunction_chain(ast)), - "has_having_without_aggregate": float(self.parser.has_having_without_agg(ast)), - "has_constant_predicate": float(self.parser.has_constant_predicate(ast)), - "has_length_empty_pattern": float(self.parser.has_length_empty_pattern(ast)), - "has_groupby_string_candidate": float(self.parser.has_groupby_string_candidate(ast)), - "has_distinct_after_groupby": float(self.parser.has_distinct_after_groupby(ast)), - "has_orderby_without_limit_subquery": float( - self.parser.has_orderby_without_limit_in_subquery(ast) - ), - "has_subquery_filter_pushdown": float(self.parser.has_subquery_filter_pushdown(ast)), - "has_top_level_select_star": float(self.parser.has_top_level_select_star(ast)), - "has_missing_limit": float(self.parser.has_missing_limit(ast)), - "has_union_not_all": float(self.parser.has_union_not_all(ast)), - "has_final_modifier": float(self.parser.has_final_modifier(ast)), - "has_throwing_cast": float(self._has_throwing_cast(ast)), - "has_async_insert_without_wait": float(self._has_async_insert_without_wait(sql)), - "has_oversized_int_candidate": float(self._has_oversized_int_candidate(sql)), - } - - def _regex_features(self, sql: str) -> FeatureMap: - return { - "has_async_insert_without_wait": float(self._has_async_insert_without_wait(sql)), - "has_oversized_int_candidate": float(self._has_oversized_int_candidate(sql)), - } - - def _function_call_count(self, ast: sqlglot.Expression) -> int: - function_types = (exp.Anonymous, exp.Cast, exp.Count, exp.Sum, exp.Avg, exp.Min, exp.Max) - return sum(1 for node in ast.walk() if isinstance(node, function_types)) - - def _aggregate_call_count(self, ast: sqlglot.Expression) -> int: - aggregate_types = (exp.Count, exp.Sum, exp.Avg, exp.Min, exp.Max) - return sum(1 for node in ast.walk() if isinstance(node, aggregate_types)) - - def _has_function_on_filter_column(self, ast: sqlglot.Expression) -> bool: - return ( - self.parser.has_todate_equality(ast) - or self.parser.has_date_part_equality(ast) - or self.parser.has_interval_start_equality(ast) - or self.parser.has_redundant_cast(ast) - ) - - def _has_throwing_cast(self, ast: sqlglot.Expression) -> bool: - for cast in ast.find_all(exp.Cast): - if isinstance(cast.this, exp.Column): - return True - for function in ast.find_all(exp.Anonymous): - name = function.name.lower() - if name.endswith(("orzero", "ornull", "ordefault")): - continue - if name.startswith(("touint", "toint", "tofloat", "tostring", "todecimal", "todate")): - return bool(function.expressions and isinstance(function.expressions[0], exp.Column)) - return False - - def _has_async_insert_without_wait(self, sql: str) -> bool: - return bool( - re.search(r"\binsert\b", sql, re.I) - and re.search(r"\basync_insert\s*=\s*1\b", sql, re.I) - and not re.search(r"\bwait_for_async_insert\s*=\s*1\b", sql, re.I) - ) - - def _has_oversized_int_candidate(self, sql: str) -> bool: - if not re.search(r"\bcreate\s+table\b", sql, re.I): - return False - return bool( - re.search( - r"\b(?:event_type|order_status|log_level|session_type|account_status|payment_type)\s+U?Int64\b", - sql, - re.I, - ) - ) - - -def ordered_feature_names(rows: list[Mapping[str, float]]) -> list[str]: - names: set[str] = set() - for row in rows: - names.update(row) - return sorted(names) diff --git a/clickadvisor/rules/detectors/D015_optimize_table_final.py b/clickadvisor/rules/detectors/D015_optimize_table_final.py deleted file mode 100644 index daf5aa6b..00000000 --- a/clickadvisor/rules/detectors/D015_optimize_table_final.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_OPTIMIZE_FINAL_RE = re.compile( - r"\bOPTIMIZE\s+TABLE\s+[\w.`\"]+.*?\bFINAL\b", - re.IGNORECASE | re.DOTALL, -) - - -class D015OptimizeTableFinal(Rule): - rule_id = "D-015" - name = "optimize_table_final" - tier = "detector" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - if not _OPTIMIZE_FINAL_RE.search(context.sql): - return None - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="high", - description=( - "OPTIMIZE TABLE ... FINAL перезаписывает все data parts в один, " - "игнорируя лимиты слияния. На больших таблицах — часы I/O и риск OOM." - ), - suggestion=( - "Используйте FINAL в SELECT вместо OPTIMIZE FINAL: " - "SELECT ... FROM t FINAL WHERE ... " - "Не запускайте OPTIMIZE FINAL в продакшене." - ), - example_before="OPTIMIZE TABLE events FINAL", - example_after="SELECT event_id FROM events FINAL WHERE dt >= today() - 7", - explain_why=( - "OPTIMIZE FINAL игнорирует max_bytes_to_merge_at_max_space_in_pool " - "и сливает части в один. Может создать часть в сотни ГБ, " - "которую невозможно разбить обратно." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/detectors/D016_alter_table_mutation.py b/clickadvisor/rules/detectors/D016_alter_table_mutation.py deleted file mode 100644 index f78990c2..00000000 --- a/clickadvisor/rules/detectors/D016_alter_table_mutation.py +++ /dev/null @@ -1,49 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_MUTATION_RE = re.compile( - r"\bALTER\s+TABLE\s+[\w.`\"]+\s+(DELETE|UPDATE)\b", - re.IGNORECASE, -) - - -class D016AlterTableMutation(Rule): - rule_id = "D-016" - name = "alter_table_mutation" - tier = "detector" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - m = _MUTATION_RE.search(context.sql) - if not m: - return None - op = m.group(1).upper() - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="high", - description=( - f"ALTER TABLE ... {op} (мутация) перезаписывает весь затронутый data part. " - "Даже изменение одной строки вызывает перезапись сотен ГБ. " - "Нельзя откатить после запуска." - ), - suggestion=( - "Для удаления данных используйте lightweight DELETE (CH >= 22.8) " - "или DROP PARTITION. " - "Для обновлений рассмотрите ReplacingMergeTree или CollapsingMergeTree." - ), - example_before="ALTER TABLE events DELETE WHERE dt < '2023-01-01'", - example_after="DELETE FROM events WHERE dt < '2023-01-01' -- CH >= 22.8", - explain_why=( - "Мутации в ClickHouse — асинхронные фоновые процессы, перезаписывающие " - "целые data parts. Продолжают выполняться после рестарта сервера. " - "При подзапросах (x IN (SELECT ...)) нагрузка на CPU/RAM многократно возрастает." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/detectors/D017_nullable_column_in_ddl.py b/clickadvisor/rules/detectors/D017_nullable_column_in_ddl.py deleted file mode 100644 index cad0f193..00000000 --- a/clickadvisor/rules/detectors/D017_nullable_column_in_ddl.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_NULLABLE_COL_RE = re.compile( - r"`?(\w+)`?\s+Nullable\s*\(\s*(\w+)", - re.IGNORECASE, -) - - -class D017NullableColumnInDDL(Rule): - rule_id = "D-017" - name = "nullable_column_in_ddl" - tier = "detector" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - m = _NULLABLE_COL_RE.search(sql) - if not m: - return None - column = m.group(1) - inner_type = m.group(2) - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="medium", - description=( - f"Колонка '{column}' объявлена как Nullable({inner_type}). " - "Nullable создаёт дополнительный файл UInt8-маски, увеличивая хранение " - "и замедляя обработку. Nullable-колонки не могут быть в table indexes." - ), - suggestion=( - f"Рассмотрите замену на {inner_type} DEFAULT 0 (для числовых) " - f"или {inner_type} DEFAULT '' (для строк), если NULL не несёт " - "семантической нагрузки." - ), - example_before=f"CREATE TABLE t ({column} Nullable({inner_type})) ENGINE = MergeTree ORDER BY tuple()", - example_after=f"CREATE TABLE t ({column} {inner_type} DEFAULT 0) ENGINE = MergeTree ORDER BY tuple()", - explain_why=( - "Nullable column consumes additional storage space и almost always " - "negatively affects performance (ClickHouse docs). " - "Nullable type field cannot be included in table indexes." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/detectors/D018_deprecated_ngrambf_tokenbf_index.py b/clickadvisor/rules/detectors/D018_deprecated_ngrambf_tokenbf_index.py deleted file mode 100644 index a6102566..00000000 --- a/clickadvisor/rules/detectors/D018_deprecated_ngrambf_tokenbf_index.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_DEPRECATED_INDEX_RE = re.compile( - r"\bINDEX\s+(\w+)\s+.*?\bTYPE\s+(ngrambf_v1|tokenbf_v1)\b", - re.IGNORECASE | re.DOTALL, -) - - -class D018DeprecatedNgramBFIndex(Rule): - rule_id = "D-018" - name = "deprecated_ngrambf_tokenbf_index" - tier = "detector" - ch_version_introduced = "0.720" - ch_version_deprecated = "26.2" - - def check(self, context: QueryContext) -> Finding | None: - m = _DEPRECATED_INDEX_RE.search(context.sql) - if not m: - return None - index_name = m.group(1) - index_type = m.group(2) - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="medium", - description=( - f"Skip index '{index_name}' использует TYPE {index_type}, " - "который устарел в ClickHouse >= 26.2. " - "Замените на text-индекс (инвертированный индекс)." - ), - suggestion=( - f"Замените на: INDEX {index_name} TYPE text GRANULARITY 1. " - "Text-индекс детерминирован, поддерживает многотерминный поиск " - "и не требует настройки размера n-gram/токенов." - ), - example_before=f"INDEX {index_name} message TYPE {index_type}(4, 1024, 2, 0) GRANULARITY 4", - example_after=f"INDEX {index_name} message TYPE text GRANULARITY 1", - explain_why=( - f"{index_type} использует вероятностный Bloom filter с false positive rate. " - "Text-индекс (инвертированный) более точен, масштабируется лучше " - "и поддерживает детерминированный поиск по токенам." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/detectors/D019_set_zero_unlimited_skip_index.py b/clickadvisor/rules/detectors/D019_set_zero_unlimited_skip_index.py deleted file mode 100644 index b6071141..00000000 --- a/clickadvisor/rules/detectors/D019_set_zero_unlimited_skip_index.py +++ /dev/null @@ -1,48 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_SET_ZERO_RE = re.compile( - r"\bINDEX\s+(\w+)\s+.*?\bTYPE\s+set\s*\(\s*0\s*\)", - re.IGNORECASE | re.DOTALL, -) - - -class D019SetZeroUnlimitedSkipIndex(Rule): - rule_id = "D-019" - name = "set_zero_unlimited_skip_index" - tier = "detector" - ch_version_introduced = "0.720" - - def check(self, context: QueryContext) -> Finding | None: - m = _SET_ZERO_RE.search(context.sql) - if not m: - return None - index_name = m.group(1) - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"Skip index '{index_name}' использует TYPE set(0) — неограниченный размер набора. " - "На высококардинальных колонках индекс не сможет пропускать блоки " - "и только замедлит слияния." - ), - suggestion=( - f"Задайте явный лимит: INDEX {index_name} TYPE set(100) GRANULARITY 4. " - "Используйте set(N) только для колонок с малым числом уникальных значений в грануле." - ), - example_before=f"INDEX {index_name} status TYPE set(0) GRANULARITY 4", - example_after=f"INDEX {index_name} status TYPE set(100) GRANULARITY 4", - explain_why=( - "set(0) означает неограниченный размер набора на гранулу. " - "При высокой кардинальности набор содержит все значения " - "и не может пропустить ни один блок, тратя память при слияниях." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R021_datetime64_zero.py b/clickadvisor/rules/tier1/R021_datetime64_zero.py deleted file mode 100644 index 8b997981..00000000 --- a/clickadvisor/rules/tier1/R021_datetime64_zero.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_DT64_ZERO_RE = re.compile( - r"`?(\w+)`?\s+DateTime64\s*\(\s*0\s*(?:,\s*'[^']*')?\s*\)", - re.IGNORECASE, -) - - -class R021DateTime64ZeroToDateTime(Rule): - rule_id = "R-021" - name = "datetime64_zero_to_datetime" - tier = "1A" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - m = _DT64_ZERO_RE.search(sql) - if not m: - return None - column = m.group(1) - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"Колонка '{column}' объявлена как DateTime64(0), " - "что семантически эквивалентно DateTime. " - "DateTime занимает 4 байта (UInt32) вместо 8 байт (Int64) DateTime64." - ), - suggestion=( - f"Замените DateTime64(0) на DateTime для колонки '{column}'. " - "Диапазон DateTime: 1970-01-01 — 2106-02-07 (UInt32 epoch)." - ), - example_before=f"CREATE TABLE t ({column} DateTime64(0)) ENGINE = MergeTree ORDER BY {column}", - example_after=f"CREATE TABLE t ({column} DateTime) ENGINE = MergeTree ORDER BY {column}", - explain_why=( - "DateTime64(0) хранит эпох-секунды как Int64 (8 байт). " - "DateTime хранит как UInt32 (4 байта). При precision=0 семантика совпадает." - ), - confidence="provable", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R022_float_monetary.py b/clickadvisor/rules/tier1/R022_float_monetary.py deleted file mode 100644 index 51acadc5..00000000 --- a/clickadvisor/rules/tier1/R022_float_monetary.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_FLOAT_COL_RE = re.compile( - r"`?(\w+)`?\s+(Float32|Float64)\b", - re.IGNORECASE, -) -_MONETARY_PARTS = frozenset( - ["amount", "price", "cost", "revenue", "fee", "total", "balance", "tax", - "payment", "charge", "salary", "income", "expense", "profit", "discount", - "rate", "value"] -) - - -def _is_monetary_name(name: str) -> bool: - parts = name.lower().split("_") - return bool(_MONETARY_PARTS.intersection(parts)) - - -class R022FloatMonetary(Rule): - rule_id = "R-022" - name = "float_monetary_column_to_decimal" - tier = "1B" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - for m in _FLOAT_COL_RE.finditer(sql): - column = m.group(1) - col_type = m.group(2) - if _is_monetary_name(column): - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"Колонка '{column}' объявлена как {col_type}, " - "но по имени предположительно хранит монетарное значение. " - "Float-арифметика не ассоциативна и даёт неточные финансовые расчёты." - ), - suggestion=( - f"Замените {col_type} на Decimal64(2) для '{column}'. " - "Decimal даёт точные результаты для SUM/AVG денежных сумм." - ), - example_before=f"CREATE TABLE t ({column} {col_type}) ENGINE = MergeTree ORDER BY tuple()", - example_after=f"CREATE TABLE t ({column} Decimal64(2)) ENGINE = MergeTree ORDER BY tuple()", - explain_why=( - f"(a + b) - a может не равняться b при Float64 из-за рounding. " - "Decimal(p, s) даёт точные целочисленные вычисления со смещённой точкой." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) - return None diff --git a/clickadvisor/rules/tier1/R023_string_datetime_column.py b/clickadvisor/rules/tier1/R023_string_datetime_column.py deleted file mode 100644 index 9f10d7b6..00000000 --- a/clickadvisor/rules/tier1/R023_string_datetime_column.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_STRING_COL_RE = re.compile( - r"`?(\w+)`?\s+String\b", - re.IGNORECASE, -) -_DATE_NAME_PARTS = frozenset( - ["date", "datetime", "timestamp", "time", "created", "updated", "modified", - "deleted", "occurred", "happened", "at", "on", "when", "dt", "ts"] -) - - -def _is_datetime_name(name: str) -> bool: - parts = name.lower().split("_") - # require at least one date-related word in name parts - if _DATE_NAME_PARTS.intersection(parts): - return True - low = name.lower() - # also catch names like 'created_at', 'event_date', 'event_time' - return any(low.endswith(s) for s in ("_at", "_date", "_time", "_ts", "_dt", "_on")) - - -class R023StringDatetimeColumn(Rule): - rule_id = "R-023" - name = "string_datetime_column_to_date" - tier = "1B" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - for m in _STRING_COL_RE.finditer(sql): - column = m.group(1) - if _is_datetime_name(column): - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"Колонка '{column}' объявлена как String, " - "но по имени предположительно хранит дату или время. " - "Числовые типы дат сжимаются Delta-кодеком и допускают date-функции напрямую." - ), - suggestion=( - f"Замените String на Date (если только дата) или DateTime " - f"(если дата и время) для колонки '{column}'. " - "Проверьте реальный формат значений." - ), - example_before=f"CREATE TABLE t ({column} String) ENGINE = MergeTree ORDER BY {column}", - example_after=f"CREATE TABLE t ({column} DateTime) ENGINE = MergeTree ORDER BY {column}", - explain_why=( - "String хранит дату как UTF-8 (~10-19 байт). " - "Date — 2 байта, DateTime — 4 байта. " - "Числовые типы поддерживают Delta-сжатие и range-индексацию." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) - return None diff --git a/clickadvisor/rules/tier1/R024_string_ip_column.py b/clickadvisor/rules/tier1/R024_string_ip_column.py deleted file mode 100644 index bfa5b139..00000000 --- a/clickadvisor/rules/tier1/R024_string_ip_column.py +++ /dev/null @@ -1,75 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_STRING_COL_RE = re.compile( - r"`?(\w+)`?\s+String\b", - re.IGNORECASE, -) -_IP_NAME_PARTS = frozenset( - ["ip", "addr", "address", "host", "peer", "remote", "client", "server", - "src", "dst", "source", "destination"] -) - -# Exact column names that strongly indicate IP -_IP_EXACT_SUFFIXES = ("_ip", "_addr", "_address", "_host", "_peer") -_IP_EXACT_NAMES = frozenset( - ["ip", "remote_addr", "client_ip", "server_ip", "src_ip", "dst_ip", - "ip_address", "remote_host", "peer_address", "client_address", - "source_ip", "destination_ip"] -) - - -def _is_ip_name(name: str) -> bool: - low = name.lower() - if low in _IP_EXACT_NAMES: - return True - if any(low.endswith(s) for s in _IP_EXACT_SUFFIXES): - return True - parts = set(low.split("_")) - # Require "ip" or "addr" in parts to avoid false positives - return bool({"ip", "addr"}.intersection(parts)) - - -class R024StringIPColumn(Rule): - rule_id = "R-024" - name = "string_ip_column_to_ipv4" - tier = "1B" - ch_version_introduced = "116.253" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - for m in _STRING_COL_RE.finditer(sql): - column = m.group(1) - if _is_ip_name(column): - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"Колонка '{column}' объявлена как String, " - "но по имени предположительно хранит IP-адрес. " - "Тип IPv4 хранит адрес в 4 байтах (UInt32) вместо ~15 байт строки." - ), - suggestion=( - f"Замените String на IPv4 для '{column}' если это IPv4-адрес, " - "или IPv6 если это IPv6. Проверьте реальный формат значений." - ), - example_before=f"CREATE TABLE t ({column} String) ENGINE = MergeTree ORDER BY tuple()", - example_after=f"CREATE TABLE t ({column} IPv4) ENGINE = MergeTree ORDER BY tuple()", - explain_why=( - "IPv4 хранит адрес как UInt32 (4 байта). " - "Строка '192.168.1.1' занимает ~11 байт. " - "IPv4 поддерживает нативные функции IPv4CIDRToRange, toIPv4." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) - return None diff --git a/clickadvisor/rules/tier1/R025_order_by_tuple.py b/clickadvisor/rules/tier1/R025_order_by_tuple.py deleted file mode 100644 index 69d79300..00000000 --- a/clickadvisor/rules/tier1/R025_order_by_tuple.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -# Matches ORDER BY tuple() or ORDER BY () -_ORDER_BY_TUPLE_RE = re.compile( - r"\bORDER\s+BY\s+(?:tuple\s*\(\s*\)|\(\s*\))", - re.IGNORECASE, -) - - -class R025OrderByTupleNoPK(Rule): - rule_id = "R-025" - name = "order_by_tuple_no_pk" - tier = "1B" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - if not _ORDER_BY_TUPLE_RE.search(sql): - return None - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="medium", - description=( - "CREATE TABLE использует ORDER BY tuple() — без первичного ключа. " - "Каждый SELECT с WHERE будет сканировать все данные без возможности " - "использовать sparse primary index." - ), - suggestion=( - "Выберите ORDER BY по колонкам, наиболее часто используемым в WHERE. " - "Например: ORDER BY (user_id, ts) для аналитики по пользователям." - ), - example_before=( - "CREATE TABLE events (user_id UInt64, ts DateTime) " - "ENGINE = MergeTree ORDER BY tuple()" - ), - example_after=( - "CREATE TABLE events (user_id UInt64, ts DateTime) " - "ENGINE = MergeTree ORDER BY (user_id, ts)" - ), - explain_why=( - "ORDER BY tuple() отключает сортировку и sparse primary index. " - "Без primary key каждый SELECT выполняет полный скан — " - "10-1000x медленнее по сравнению с правильным ORDER BY." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R026_sum_case_to_countif.py b/clickadvisor/rules/tier1/R026_sum_case_to_countif.py deleted file mode 100644 index d737a670..00000000 --- a/clickadvisor/rules/tier1/R026_sum_case_to_countif.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -# Matches SUM(CASE WHEN ... THEN 1 ELSE 0 END) or COUNT(CASE WHEN ... THEN 1 END) -_SUM_CASE_ONE_RE = re.compile( - r"\b(?:SUM|COUNT)\s*\(\s*CASE\s+WHEN\s+(.+?)\s+THEN\s+1\b(?:\s+ELSE\s+0\s*)?\s*END\s*\)", - re.IGNORECASE | re.DOTALL, -) - - -class R026SumCaseToCountIf(Rule): - rule_id = "R-026" - name = "sum_case_to_countif" - tier = "1A" - ch_version_introduced = "1.23" - - def check(self, context: QueryContext) -> Finding | None: - m = _SUM_CASE_ONE_RE.search(context.sql) - if not m: - return None - cond = m.group(1).strip() - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - "SUM(CASE WHEN ... THEN 1 ELSE 0 END) или COUNT(CASE WHEN ... THEN 1 END) " - "эквивалентно countIf(cond) — встроенному комбинатору ClickHouse." - ), - suggestion=f"Замените на countIf({cond})", - example_before=f"SUM(CASE WHEN {cond} THEN 1 ELSE 0 END)", - example_after=f"countIf({cond})", - explain_why=( - "countIf(cond) — синтаксический сахар, семантически идентичен " - "COUNT(CASE WHEN cond THEN 1 END). Без материализации CASE-выражения." - ), - confidence="provable", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R027_sum_case_col_to_sumif.py b/clickadvisor/rules/tier1/R027_sum_case_col_to_sumif.py deleted file mode 100644 index 43399782..00000000 --- a/clickadvisor/rules/tier1/R027_sum_case_col_to_sumif.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -# Matches SUM(CASE WHEN cond THEN col_or_expr ELSE 0 END) -# Does NOT match THEN 1 (handled by R-026) -_SUM_CASE_COL_RE = re.compile( - r"\bSUM\s*\(\s*CASE\s+WHEN\s+(.+?)\s+THEN\s+((?!1\b)[^\s][^)]+?)\s+ELSE\s+0\s*END\s*\)", - re.IGNORECASE | re.DOTALL, -) - - -class R027SumCaseColToSumIf(Rule): - rule_id = "R-027" - name = "sum_case_col_to_sumif" - tier = "1A" - ch_version_introduced = "1.23" - - def check(self, context: QueryContext) -> Finding | None: - m = _SUM_CASE_COL_RE.search(context.sql) - if not m: - return None - cond = m.group(1).strip() - col = m.group(2).strip() - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - "SUM(CASE WHEN cond THEN col ELSE 0 END) эквивалентно " - "sumIf(col, cond) — встроенному комбинатору ClickHouse." - ), - suggestion=f"Замените на sumIf({col}, {cond})", - example_before=f"SUM(CASE WHEN {cond} THEN {col} ELSE 0 END)", - example_after=f"sumIf({col}, {cond})", - explain_why=( - "sumIf(col, cond) применяет сложение только к строкам где cond=true. " - "Математически идентично SUM(CASE WHEN ... ELSE 0 END) при ELSE 0." - ), - confidence="provable", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R028_coalesce_to_ifnull.py b/clickadvisor/rules/tier1/R028_coalesce_to_ifnull.py deleted file mode 100644 index 31c2c92d..00000000 --- a/clickadvisor/rules/tier1/R028_coalesce_to_ifnull.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -# Matches COALESCE(arg1, arg2) with exactly 2 arguments (no nested commas at top level) -_COALESCE_TWO_RE = re.compile( - r"\bCOALESCE\s*\(\s*([^,()]+)\s*,\s*([^,()]+)\s*\)", - re.IGNORECASE, -) - - -class R028CoalesceToIfNull(Rule): - rule_id = "R-028" - name = "coalesce_two_args_to_ifnull" - tier = "1A" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - m = _COALESCE_TWO_RE.search(context.sql) - if not m: - return None - arg1 = m.group(1).strip() - arg2 = m.group(2).strip() - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"COALESCE({arg1}, {arg2}) с двумя аргументами полностью эквивалентен " - f"ifNull({arg1}, {arg2})." - ), - suggestion=f"Замените на ifNull({arg1}, {arg2})", - example_before=f"COALESCE({arg1}, {arg2})", - example_after=f"ifNull({arg1}, {arg2})", - explain_why=( - "ifNull(x, y) — специализированная функция без overhead varargs-перебора. " - "Семантически идентична COALESCE с двумя аргументами." - ), - confidence="provable", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R029_lower_like_to_ilike.py b/clickadvisor/rules/tier1/R029_lower_like_to_ilike.py deleted file mode 100644 index da6fafda..00000000 --- a/clickadvisor/rules/tier1/R029_lower_like_to_ilike.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -# Matches lower(col) LIKE 'pattern' -_LOWER_LIKE_RE = re.compile( - r"\blower\s*\(\s*(\w+)\s*\)\s+LIKE\s+('[^']*')", - re.IGNORECASE, -) - - -class R029LowerLikeToILike(Rule): - rule_id = "R-029" - name = "lower_col_like_to_ilike" - tier = "1A" - ch_version_introduced = "22.6" - - def check(self, context: QueryContext) -> Finding | None: - m = _LOWER_LIKE_RE.search(context.sql) - if not m: - return None - column = m.group(1) - pattern = m.group(2) - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"lower({column}) LIKE {pattern} эквивалентен " - f"{column} ILIKE {pattern}. " - "ILIKE — нативный оператор ClickHouse (с версии 22.6)." - ), - suggestion=f"Замените на {column} ILIKE {pattern}", - example_before=f"lower({column}) LIKE {pattern}", - example_after=f"{column} ILIKE {pattern}", - explain_why=( - "ILIKE выполняет регистронезависимое сравнение без явного вызова lower(). " - "Упрощает план запроса и улучшает читаемость кода." - ), - confidence="provable", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R030_not_in_singleton.py b/clickadvisor/rules/tier1/R030_not_in_singleton.py deleted file mode 100644 index 7da3e1b2..00000000 --- a/clickadvisor/rules/tier1/R030_not_in_singleton.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -# Matches col NOT IN (single_value) — one numeric or string literal, no comma -_NOT_IN_SINGLETON_RE = re.compile( - r"(\w+)\s+NOT\s+IN\s*\(\s*('[^']*'|\d+(?:\.\d+)?)\s*\)", - re.IGNORECASE, -) - - -class R030NotInSingleton(Rule): - rule_id = "R-030" - name = "not_in_singleton_to_not_equal" - tier = "1A" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - m = _NOT_IN_SINGLETON_RE.search(context.sql) - if not m: - return None - col = m.group(1) - val = m.group(2) - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"{col} NOT IN ({val}) с одним значением эквивалентен " - f"{col} != {val} для не-Nullable колонок." - ), - suggestion=f"Замените на {col} != {val}", - example_before=f"WHERE {col} NOT IN ({val})", - example_after=f"WHERE {col} != {val}", - explain_why=( - "NOT IN с одним элементом строит hash set вместо прямого " - "скалярного сравнения. Для не-Nullable колонок результат идентичен !=." - ), - confidence="provable", - ch_version_introduced=self.ch_version_introduced, - ) diff --git a/clickadvisor/rules/tier1/R031_string_uuid_column.py b/clickadvisor/rules/tier1/R031_string_uuid_column.py deleted file mode 100644 index 83d0fe12..00000000 --- a/clickadvisor/rules/tier1/R031_string_uuid_column.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import re - -from clickadvisor.core.models import Finding, QueryContext -from clickadvisor.rules.base import Rule - -_CREATE_TABLE_RE = re.compile(r"\bCREATE\s+TABLE\b", re.IGNORECASE) -_STRING_COL_RE = re.compile( - r"`?(\w+)`?\s+String\b", - re.IGNORECASE, -) -_UUID_NAME_PARTS = frozenset(["uuid", "guid", "uid"]) -_UUID_EXACT_SUFFIXES = ("_uuid", "_guid", "_uid") -_UUID_COLUMN_NAMES = frozenset( - ["trace_id", "span_id", "request_id", "correlation_id", - "uuid", "guid", "uid", "object_id"] -) - - -def _is_uuid_name(name: str) -> bool: - low = name.lower() - if low in _UUID_COLUMN_NAMES: - return True - if any(low.endswith(s) for s in _UUID_EXACT_SUFFIXES): - return True - parts = set(low.split("_")) - return bool(_UUID_NAME_PARTS.intersection(parts)) - - -class R031StringUUIDColumn(Rule): - rule_id = "R-031" - name = "string_uuid_column_to_uuid_type" - tier = "1B" - ch_version_introduced = "1.0" - - def check(self, context: QueryContext) -> Finding | None: - sql = context.sql - if not _CREATE_TABLE_RE.search(sql): - return None - for m in _STRING_COL_RE.finditer(sql): - column = m.group(1) - if _is_uuid_name(column): - return Finding( - rule_id=self.rule_id, - rule_name=self.name, - tier=self.tier, - severity="low", - description=( - f"Колонка '{column}' объявлена как String, " - "но по имени предположительно хранит UUID. " - "UUID-тип хранит 16 байт вместо ~36 байт строки с дефисами." - ), - suggestion=( - f"Замените String на UUID для '{column}'. " - "Проверьте, что все значения — валидные UUID-строки." - ), - example_before=f"CREATE TABLE t ({column} String) ENGINE = MergeTree ORDER BY {column}", - example_after=f"CREATE TABLE t ({column} UUID) ENGINE = MergeTree ORDER BY {column}", - explain_why=( - "UUID хранит 128 бит (16 байт) в бинарном виде. " - "String UUID занимает ~36 байт. Экономия ~2.25x плюс нативные UUID-функции." - ), - confidence="advisory", - ch_version_introduced=self.ch_version_introduced, - ) - return None diff --git a/data/ml/features_dataset.jsonl b/data/ml/features_dataset.jsonl deleted file mode 100644 index 85886684..00000000 --- a/data/ml/features_dataset.jsonl +++ /dev/null @@ -1,162 +0,0 @@ -{"case_id": "synthetic_expanded_d003_001", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 29}, "labels": ["select_star_on_wide_table"], "split": "train"} -{"case_id": "synthetic_expanded_d003_002", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 49}, "labels": ["select_star_on_wide_table"], "split": "train"} -{"case_id": "synthetic_expanded_d003_003", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 51}, "labels": ["select_star_on_wide_table"], "split": "train"} -{"case_id": "synthetic_expanded_d003_004", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 56}, "labels": ["select_star_on_wide_table"], "split": "train"} -{"case_id": "synthetic_expanded_d003_005", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 48}, "labels": ["select_star_on_wide_table"], "split": "train"} -{"case_id": "synthetic_expanded_d003_006", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 54}, "labels": ["select_star_on_wide_table"], "split": "train"} -{"case_id": "synthetic_expanded_d004_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 3, "where_clause_depth": 2, "query_length_chars": 74}, "labels": ["missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_d004_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 3, "where_clause_depth": 2, "query_length_chars": 57}, "labels": ["missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_d004_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 3, "where_clause_depth": 2, "query_length_chars": 70}, "labels": ["missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_d004_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 3, "where_clause_depth": 2, "query_length_chars": 74}, "labels": ["missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_d004_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 3, "where_clause_depth": 2, "query_length_chars": 59}, "labels": ["missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_d004_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 3, "where_clause_depth": 2, "query_length_chars": 75}, "labels": ["missing_limit_on_unbounded_result"], "split": "test"} -{"case_id": "synthetic_expanded_d007_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 1, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 50}, "labels": ["final_modifier_usage"], "split": "train"} -{"case_id": "synthetic_expanded_d007_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 1, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 54}, "labels": ["final_modifier_usage"], "split": "train"} -{"case_id": "synthetic_expanded_d007_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 1, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 56}, "labels": ["final_modifier_usage"], "split": "train"} -{"case_id": "synthetic_expanded_d007_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 1, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 51}, "labels": ["final_modifier_usage"], "split": "train"} -{"case_id": "synthetic_expanded_d007_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 1, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 56}, "labels": ["final_modifier_usage"], "split": "train"} -{"case_id": "synthetic_expanded_d007_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 1, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 52}, "labels": ["final_modifier_usage"], "split": "train"} -{"case_id": "synthetic_expanded_d014_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 1, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 62}, "labels": ["async_insert_without_wait_flag"], "split": "train"} -{"case_id": "synthetic_expanded_d014_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 1, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 64}, "labels": ["async_insert_without_wait_flag"], "split": "test"} -{"case_id": "synthetic_expanded_d014_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 1, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 62}, "labels": ["async_insert_without_wait_flag"], "split": "train"} -{"case_id": "synthetic_expanded_d014_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 1, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 67}, "labels": ["async_insert_without_wait_flag"], "split": "test"} -{"case_id": "synthetic_expanded_d014_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 1, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 59}, "labels": ["async_insert_without_wait_flag"], "split": "train"} -{"case_id": "synthetic_expanded_d014_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 1, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 61}, "labels": ["async_insert_without_wait_flag"], "split": "train"} -{"case_id": "synthetic_expanded_negative_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 107}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 2, "query_length_chars": 82}, "labels": [], "split": "test"} -{"case_id": "synthetic_expanded_negative_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 63}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 2, "query_length_chars": 72}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 71}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 1, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 73}, "labels": [], "split": "test"} -{"case_id": "synthetic_expanded_negative_007", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 34}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_008", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 29}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_009", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 49}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_010", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 74}, "labels": [], "split": "test"} -{"case_id": "synthetic_expanded_negative_011", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 44}, "labels": [], "split": "test"} -{"case_id": "synthetic_expanded_negative_012", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 73}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_013", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 74}, "labels": [], "split": "test"} -{"case_id": "synthetic_expanded_negative_014", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 1, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 87}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_015", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 46}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_016", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 46}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_017", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 56}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_018", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 48}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_negative_019", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 44}, "labels": [], "split": "test"} -{"case_id": "synthetic_expanded_negative_020", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 41}, "labels": [], "split": "train"} -{"case_id": "synthetic_expanded_r001_001", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 42}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "train"} -{"case_id": "synthetic_expanded_r001_002", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 43}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "test"} -{"case_id": "synthetic_expanded_r001_003", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 65}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "train"} -{"case_id": "synthetic_expanded_r001_004", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 88}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "train"} -{"case_id": "synthetic_expanded_r001_005", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 47}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "train"} -{"case_id": "synthetic_expanded_r001_006", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 65}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "train"} -{"case_id": "synthetic_expanded_r001_007", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 51}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "test"} -{"case_id": "synthetic_expanded_r001_008", "features": {"has_count_distinct": 1, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 70}, "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], "split": "test"} -{"case_id": "synthetic_expanded_r003_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 55}, "labels": ["exact_quantile_candidate"], "split": "test"} -{"case_id": "synthetic_expanded_r003_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 48}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r003_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 53}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r003_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 81}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r003_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 51}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r003_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 56}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r003_007", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 54}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r003_008", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 1, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 51}, "labels": ["exact_quantile_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r004_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 58}, "labels": ["count_star_distinct_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r004_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 59}, "labels": ["count_star_distinct_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r004_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 81}, "labels": ["count_star_distinct_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r004_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 63}, "labels": ["count_star_distinct_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r004_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 63}, "labels": ["count_star_distinct_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r004_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 60}, "labels": ["count_star_distinct_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r005_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 66}, "labels": ["function_on_datetime_filter", "unsafe_cast_without_default"], "split": "test"} -{"case_id": "synthetic_expanded_r005_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 56}, "labels": ["function_on_datetime_filter", "unsafe_cast_without_default"], "split": "test"} -{"case_id": "synthetic_expanded_r005_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 63}, "labels": ["function_on_datetime_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r005_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 68}, "labels": ["function_on_datetime_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r005_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 70}, "labels": ["function_on_datetime_filter", "unsafe_cast_without_default"], "split": "test"} -{"case_id": "synthetic_expanded_r005_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 70}, "labels": ["function_on_datetime_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r006_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 62}, "labels": ["date_part_filter_to_range"], "split": "test"} -{"case_id": "synthetic_expanded_r006_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 56}, "labels": ["date_part_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r006_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 56}, "labels": ["date_part_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r006_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 76}, "labels": ["date_part_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r006_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 64}, "labels": ["date_part_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r006_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 66}, "labels": ["date_part_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r007_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 72}, "labels": ["interval_start_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r007_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 81}, "labels": ["interval_start_filter_to_range"], "split": "test"} -{"case_id": "synthetic_expanded_r007_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 96}, "labels": ["interval_start_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r007_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 84}, "labels": ["interval_start_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r007_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 84}, "labels": ["interval_start_filter_to_range"], "split": "train"} -{"case_id": "synthetic_expanded_r007_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 86}, "labels": ["interval_start_filter_to_range"], "split": "test"} -{"case_id": "synthetic_expanded_r008_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 63}, "labels": ["redundant_cast_on_filter", "unsafe_cast_without_default"], "split": "test"} -{"case_id": "synthetic_expanded_r008_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 58}, "labels": ["redundant_cast_on_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r008_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 63}, "labels": ["redundant_cast_on_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r008_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 58}, "labels": ["redundant_cast_on_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r008_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 64}, "labels": ["redundant_cast_on_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r008_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 62}, "labels": ["redundant_cast_on_filter", "unsafe_cast_without_default"], "split": "train"} -{"case_id": "synthetic_expanded_r009_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 1, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 50}, "labels": ["singleton_in_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r009_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 1, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 50}, "labels": ["singleton_in_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r009_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 1, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 49}, "labels": ["singleton_in_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r009_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 1, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 56}, "labels": ["singleton_in_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r009_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 1, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 49}, "labels": ["singleton_in_predicate"], "split": "test"} -{"case_id": "synthetic_expanded_r009_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 1, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 54}, "labels": ["singleton_in_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r010_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 1, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 4, "query_length_chars": 83}, "labels": ["disjunction_chain_to_in"], "split": "train"} -{"case_id": "synthetic_expanded_r010_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 1, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 4, "query_length_chars": 83}, "labels": ["disjunction_chain_to_in"], "split": "train"} -{"case_id": "synthetic_expanded_r010_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 1, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 4, "query_length_chars": 91}, "labels": ["disjunction_chain_to_in"], "split": "train"} -{"case_id": "synthetic_expanded_r010_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 1, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 4, "query_length_chars": 98}, "labels": ["disjunction_chain_to_in"], "split": "test"} -{"case_id": "synthetic_expanded_r010_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 1, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 4, "query_length_chars": 84}, "labels": ["disjunction_chain_to_in"], "split": "test"} -{"case_id": "synthetic_expanded_r010_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 1, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 4, "query_length_chars": 91}, "labels": ["disjunction_chain_to_in"], "split": "test"} -{"case_id": "synthetic_expanded_r011_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 1, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 94}, "labels": ["having_without_aggregate"], "split": "train"} -{"case_id": "synthetic_expanded_r011_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 1, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 98}, "labels": ["having_without_aggregate"], "split": "test"} -{"case_id": "synthetic_expanded_r011_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 1, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 104}, "labels": ["having_without_aggregate"], "split": "train"} -{"case_id": "synthetic_expanded_r011_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 1, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 104}, "labels": ["having_without_aggregate"], "split": "train"} -{"case_id": "synthetic_expanded_r011_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 1, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 112}, "labels": ["having_without_aggregate"], "split": "test"} -{"case_id": "synthetic_expanded_r011_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 1, "has_having_without_aggregate": 1, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 100}, "labels": ["having_without_aggregate"], "split": "train"} -{"case_id": "synthetic_expanded_r012_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 1, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 53}, "labels": ["constant_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r012_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 1, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 56}, "labels": ["constant_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r012_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 1, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 57}, "labels": ["constant_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r012_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 1, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 62}, "labels": ["constant_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r012_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 1, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 52}, "labels": ["constant_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r012_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 1, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 60}, "labels": ["constant_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r013_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 1, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 51}, "labels": ["length_empty_predicate"], "split": "test"} -{"case_id": "synthetic_expanded_r013_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 1, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 50}, "labels": ["length_empty_predicate"], "split": "test"} -{"case_id": "synthetic_expanded_r013_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 1, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 50}, "labels": ["length_empty_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r013_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 1, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 52}, "labels": ["length_empty_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r013_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 1, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 56}, "labels": ["length_empty_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r013_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 1, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 3, "query_length_chars": 55}, "labels": ["length_empty_predicate"], "split": "train"} -{"case_id": "synthetic_expanded_r014_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 1, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 43}, "labels": ["groupby_string_hash_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r014_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 1, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 51}, "labels": ["groupby_string_hash_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r014_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 1, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 49}, "labels": ["groupby_string_hash_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r014_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 1, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 51}, "labels": ["groupby_string_hash_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r014_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 1, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 46}, "labels": ["groupby_string_hash_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r014_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 1, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 51}, "labels": ["groupby_string_hash_candidate"], "split": "train"} -{"case_id": "synthetic_expanded_r015_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 92}, "labels": ["distinct_after_groupby"], "split": "train"} -{"case_id": "synthetic_expanded_r015_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 128}, "labels": ["distinct_after_groupby"], "split": "train"} -{"case_id": "synthetic_expanded_r015_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 139}, "labels": ["distinct_after_groupby"], "split": "train"} -{"case_id": "synthetic_expanded_r015_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 139}, "labels": ["distinct_after_groupby"], "split": "train"} -{"case_id": "synthetic_expanded_r015_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 139}, "labels": ["distinct_after_groupby"], "split": "test"} -{"case_id": "synthetic_expanded_r015_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 1, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 1, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 2, "where_clause_depth": 0, "query_length_chars": 150}, "labels": ["distinct_after_groupby"], "split": "test"} -{"case_id": "synthetic_expanded_r016_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 1, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 63}, "labels": ["orderby_without_limit_in_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r016_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 1, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 53}, "labels": ["orderby_without_limit_in_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r016_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 1, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 63}, "labels": ["orderby_without_limit_in_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r016_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 1, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 65}, "labels": ["orderby_without_limit_in_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r016_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 1, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 67}, "labels": ["orderby_without_limit_in_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r016_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 1, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 67}, "labels": ["orderby_without_limit_in_subquery"], "split": "train"} -{"case_id": "synthetic_expanded_r017_001", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 1, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 79}, "labels": ["subquery_filter_pushdown", "select_star_on_wide_table", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r017_002", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 1, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 77}, "labels": ["subquery_filter_pushdown", "select_star_on_wide_table", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r017_003", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 1, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 81}, "labels": ["subquery_filter_pushdown", "select_star_on_wide_table", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r017_004", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 1, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 83}, "labels": ["subquery_filter_pushdown", "select_star_on_wide_table", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r017_005", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 1, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 79}, "labels": ["subquery_filter_pushdown", "select_star_on_wide_table", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r017_006", "features": {"has_count_distinct": 0, "has_select_star": 1, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 1, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 1, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 2, "query_length_chars": 83}, "labels": ["subquery_filter_pushdown", "select_star_on_wide_table", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r018_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 69}, "labels": ["union_without_all"], "split": "train"} -{"case_id": "synthetic_expanded_r018_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 71}, "labels": ["union_without_all"], "split": "train"} -{"case_id": "synthetic_expanded_r018_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 80}, "labels": ["union_without_all"], "split": "train"} -{"case_id": "synthetic_expanded_r018_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 71}, "labels": ["union_without_all"], "split": "train"} -{"case_id": "synthetic_expanded_r018_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 75}, "labels": ["union_without_all"], "split": "train"} -{"case_id": "synthetic_expanded_r018_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 1, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 2, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 65}, "labels": ["union_without_all"], "split": "train"} -{"case_id": "synthetic_expanded_r019_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 93}, "labels": ["oversized_uint_type_narrowing"], "split": "train"} -{"case_id": "synthetic_expanded_r019_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 96}, "labels": ["oversized_uint_type_narrowing"], "split": "test"} -{"case_id": "synthetic_expanded_r019_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 82}, "labels": ["oversized_uint_type_narrowing"], "split": "test"} -{"case_id": "synthetic_expanded_r019_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 103}, "labels": ["oversized_uint_type_narrowing"], "split": "train"} -{"case_id": "synthetic_expanded_r019_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 95}, "labels": ["oversized_uint_type_narrowing"], "split": "train"} -{"case_id": "synthetic_expanded_r019_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 0, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 0, "has_cast_without_default": 0, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 0, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 0, "where_clause_depth": 0, "query_length_chars": 103}, "labels": ["oversized_uint_type_narrowing"], "split": "train"} -{"case_id": "synthetic_expanded_r020_001", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 44}, "labels": ["unsafe_cast_without_default", "redundant_cast_on_filter", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r020_002", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 37}, "labels": ["unsafe_cast_without_default", "redundant_cast_on_filter", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r020_003", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 47}, "labels": ["unsafe_cast_without_default", "redundant_cast_on_filter", "missing_limit_on_unbounded_result"], "split": "test"} -{"case_id": "synthetic_expanded_r020_004", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 43}, "labels": ["unsafe_cast_without_default", "redundant_cast_on_filter", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r020_005", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 45}, "labels": ["unsafe_cast_without_default", "redundant_cast_on_filter", "missing_limit_on_unbounded_result"], "split": "train"} -{"case_id": "synthetic_expanded_r020_006", "features": {"has_count_distinct": 0, "has_select_star": 0, "has_final_modifier": 0, "has_union": 0, "has_union_all": 0, "has_group_by": 0, "has_group_by_string_column": 0, "has_having": 0, "has_having_without_aggregate": 0, "has_function_on_filter_column": 1, "has_subquery": 0, "has_subquery_with_orderby_no_limit": 0, "has_nested_subquery_filter": 0, "has_or_chain_same_column": 0, "has_in_with_single_value": 0, "has_quantile_exact": 0, "has_cast": 1, "has_cast_without_default": 1, "has_async_insert_setting": 0, "has_async_insert_without_wait": 0, "has_limit": 0, "has_no_limit": 1, "has_constant_predicate": 0, "has_length_zero_check": 0, "table_count": 1, "column_count_in_select": 1, "where_clause_depth": 0, "query_length_chars": 39}, "labels": ["unsafe_cast_without_default", "redundant_cast_on_filter", "missing_limit_on_unbounded_result"], "split": "train"} diff --git a/docs/rules/cards/D-015-optimize_table_final.yaml b/docs/rules/cards/D-015-optimize_table_final.yaml deleted file mode 100644 index 9e1c1d53..00000000 --- a/docs/rules/cards/D-015-optimize_table_final.yaml +++ /dev/null @@ -1,40 +0,0 @@ -id: D-015 -name: optimize_table_final -tier: detector -category: ddl_operations -status: proposed -statement: 'OPTIMIZE TABLE ... FINAL принудительно сливает все data parts в один, - игнорируя лимит max_bytes_to_merge_at_max_space_in_pool. На больших таблицах - ведёт к многочасовой I/O нагрузке, возможному OOM и созданию частей в сотни ГБ, - которые невозможно разбить обратно.' -preconditions: - syntactic: - - Запрос содержит OPTIMIZE TABLE ... FINAL - semantic: [] - data: [] -proof: - status: advisory - notes: 'Документировано в ClickHouse docs: OPTIMIZE FINAL игнорирует стандартные - лимиты слияния. Altinity KB: не рекомендуется для таблиц с более 10 млн строк.' -recommendation_template: 'OPTIMIZE TABLE ... FINAL обнаружен в SQL. Эта операция - перезаписывает все data parts в один, игнорируя max_bytes_to_merge_at_max_space_in_pool. - На больших таблицах это многочасовая I/O нагрузка и риск OOM. Используйте вместо - этого FINAL-квалификатор в SELECT: SELECT ... FROM t FINAL — он гарантирует - дедупликацию при чтении без принудительного слияния.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: 'OPTIMIZE TABLE events FINAL' -example_after: 'SELECT event_id, user_id FROM events FINAL WHERE dt >= today() - 7' -expected_speedup: - estimate: null - measurement_method: null -risks: -- После выполнения OPTIMIZE FINAL последствия необратимы без ручного разбиения части -- Создание части в сотни ГБ делает будущие мутации и ALTER крайне медленными -severity: high -opt_in: false -references: -- https://clickhouse.com/docs/best-practices/avoid-optimize-final -- https://kb.altinity.com/altinity-kb-queries-and-syntax/altinity-kb-optimize-vs-optimize-final/ diff --git a/docs/rules/cards/D-016-alter_table_mutation.yaml b/docs/rules/cards/D-016-alter_table_mutation.yaml deleted file mode 100644 index d6b1d434..00000000 --- a/docs/rules/cards/D-016-alter_table_mutation.yaml +++ /dev/null @@ -1,41 +0,0 @@ -id: D-016 -name: alter_table_mutation -tier: detector -category: ddl_operations -status: proposed -statement: 'ALTER TABLE ... DELETE или ALTER TABLE ... UPDATE — мутации перезаписывают - весь data part, затронутый изменением. Даже изменение одной строки вызывает - перезапись сотен ГБ. Нельзя откатить после запуска.' -preconditions: - syntactic: - - Запрос начинается с ALTER TABLE и содержит DELETE или UPDATE - semantic: [] - data: [] -proof: - status: advisory - notes: 'Документировано в ClickHouse docs: мутации — асинхронные фоновые - процессы, перезаписывающие целые data parts. Не блокируют INSERT, но создают - огромную I/O нагрузку и продолжают выполняться после рестарта сервера.' -recommendation_template: 'ALTER TABLE ... DELETE/UPDATE (мутация) обнаружен в SQL. - Мутации в ClickHouse перезаписывают весь затронутый data part — даже при изменении - одной строки. Рассмотрите альтернативы: для удаления данных — lightweight DELETE - (CH >= 22.8) или DROP PARTITION; для уточнения данных — ReplacingMergeTree или - CollapsingMergeTree.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: 'ALTER TABLE events DELETE WHERE dt < ''2023-01-01''' -example_after: 'DELETE FROM events WHERE dt < ''2023-01-01'' -- lightweight delete, - CH >= 22.8' -expected_speedup: - estimate: null - measurement_method: null -risks: -- Мутацию нельзя откатить после запуска -- При сложных подзапросах (x IN (SELECT ...)) нагрузка на CPU и RAM многократно возрастает -severity: high -opt_in: false -references: -- https://clickhouse.com/docs/best-practices/avoid-mutations -- https://clickhouse.com/docs/optimize/avoid-mutations diff --git a/docs/rules/cards/D-017-nullable_column_in_ddl.yaml b/docs/rules/cards/D-017-nullable_column_in_ddl.yaml deleted file mode 100644 index 6af97e32..00000000 --- a/docs/rules/cards/D-017-nullable_column_in_ddl.yaml +++ /dev/null @@ -1,42 +0,0 @@ -id: D-017 -name: nullable_column_in_ddl -tier: detector -category: schema_types -status: proposed -statement: 'CREATE TABLE содержит колонку типа Nullable(T). Nullable создаёт - отдельный файл UInt8-маски для трекинга NULL-значений, что увеличивает хранение - и почти всегда снижает производительность.' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - В определении колонки присутствует тип Nullable(...) - semantic: [] - data: [] -proof: - status: advisory - notes: 'Документировано в ClickHouse docs: Nullable column consumes additional - storage space и almost always negatively affects performance. Nullable type - field cannot be included in table indexes.' -recommendation_template: 'Колонка {column} объявлена как Nullable({inner_type}). - Nullable создаёт дополнительный файл UInt8-маски. Если NULL не несёт семантической - нагрузки (отсутствие значения), рассмотрите замену на {inner_type} DEFAULT 0 - или {inner_type} DEFAULT ''''.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE events (user_id UInt64, score Nullable(Float64))\n\ - ENGINE = MergeTree ORDER BY user_id" -example_after: "CREATE TABLE events (user_id UInt64, score Float64 DEFAULT 0.0)\n\ - ENGINE = MergeTree ORDER BY user_id" -expected_speedup: - estimate: '5-15%' - measurement_method: 'Сравнение времени выполнения SELECT с агрегациями по Nullable - и не-Nullable колонкам.' -risks: -- Если NULL семантически значим (отличается от «нет данных» и нуля), замена нарушит логику -severity: medium -opt_in: false -references: -- https://clickhouse.com/docs/optimize/avoid-nullable-columns -- https://clickhouse.com/docs/sql-reference/data-types/nullable diff --git a/docs/rules/cards/D-018-deprecated_ngrambf_tokenbf_index.yaml b/docs/rules/cards/D-018-deprecated_ngrambf_tokenbf_index.yaml deleted file mode 100644 index c5489cbd..00000000 --- a/docs/rules/cards/D-018-deprecated_ngrambf_tokenbf_index.yaml +++ /dev/null @@ -1,38 +0,0 @@ -id: D-018 -name: deprecated_ngrambf_tokenbf_index -tier: detector -category: skip_index -status: proposed -statement: 'DDL содержит skip index типа ngrambf_v1 или tokenbf_v1. Оба типа - устарели начиная с ClickHouse 26.2 и заменены более эффективным text-индексом - (инвертированный индекс).' -preconditions: - syntactic: - - DDL содержит INDEX ... TYPE ngrambf_v1 или INDEX ... TYPE tokenbf_v1 - semantic: [] - data: [] -proof: - status: advisory - notes: 'Документировано в ClickHouse docs (use-data-skipping-indices): tokenbf_v1 - и ngrambf_v1 deprecated в CH >= 26.2 в пользу text indexes.' -recommendation_template: 'Skip index {index_name} использует тип {index_type}, - который устарел в CH >= 26.2. Замените на TEXT-индекс: INDEX {index_name} - {column} TYPE text GRANULARITY 1. Text-индекс детерминирован, поддерживает - многотерминный поиск и не требует настройки размера токенов.' -ch_version: - introduced: '0.720' - deprecated: '26.2' - last_validated: '25.3' -example_before: "INDEX idx_log message TYPE ngrambf_v1(4, 1024, 2, 0) GRANULARITY\ - \ 4" -example_after: "INDEX idx_log message TYPE text GRANULARITY 1" -expected_speedup: - estimate: null - measurement_method: null -risks: -- text-индекс требует CH >= 24.1; в старых версиях недоступен -severity: medium -opt_in: false -references: -- https://clickhouse.com/docs/best-practices/use-data-skipping-indices-where-appropriate -- https://clickhouse.com/docs/optimize/skipping-indexes diff --git a/docs/rules/cards/D-019-set_zero_unlimited_skip_index.yaml b/docs/rules/cards/D-019-set_zero_unlimited_skip_index.yaml deleted file mode 100644 index 3a3bfac9..00000000 --- a/docs/rules/cards/D-019-set_zero_unlimited_skip_index.yaml +++ /dev/null @@ -1,40 +0,0 @@ -id: D-019 -name: set_zero_unlimited_skip_index -tier: detector -category: skip_index -status: proposed -statement: 'DDL содержит skip index типа set(0). Значение 0 означает неограниченный - набор значений на блок — индекс будет накапливать все уникальные значения - в грануле без ограничения. На высококардинальных колонках это ведёт к огромному - потреблению памяти при слияниях и нулевому эффекту пропуска блоков.' -preconditions: - syntactic: - - DDL содержит INDEX ... TYPE set(0) - semantic: [] - data: [] -proof: - status: advisory - notes: 'Документировано в ClickHouse docs: set(N) tracks a set of values up - to N per block. N=0 означает неограниченный размер — эффективен только - для колонок с гарантированно малым числом уникальных значений в грануле.' -recommendation_template: 'Skip index {index_name} использует TYPE set(0) — - неограниченный размер набора. Если колонка имеет высокую кардинальность - в пределах гранулы, индекс не сможет пропускать блоки и только замедлит - слияния. Используйте set(N) с явным ограничением (например, set(100)) - или выберите другой тип индекса (minmax, bloom_filter).' -ch_version: - introduced: '0.720' - deprecated: null - last_validated: '25.3' -example_before: "INDEX idx_status status TYPE set(0) GRANULARITY 4" -example_after: "INDEX idx_status status TYPE set(100) GRANULARITY 4" -expected_speedup: - estimate: null - measurement_method: null -risks: -- Если колонка имеет низкую кардинальность, set(0) работает корректно -severity: low -opt_in: false -references: -- https://clickhouse.com/docs/best-practices/use-data-skipping-indices-where-appropriate -- https://clickhouse.com/docs/optimize/skipping-indexes diff --git a/docs/rules/cards/E-012-join_use_nulls_overhead.yaml b/docs/rules/cards/E-012-join_use_nulls_overhead.yaml deleted file mode 100644 index 801dbe16..00000000 --- a/docs/rules/cards/E-012-join_use_nulls_overhead.yaml +++ /dev/null @@ -1,46 +0,0 @@ -id: E-012 -name: join_use_nulls_overhead -tier: env -category: join_settings -status: proposed -statement: 'join_use_nulls = 1 оборачивает результирующие колонки внешних - JOIN (LEFT/RIGHT/FULL) в Nullable, добавляя дополнительный UInt8-столбец маски - и overhead при обработке. Значение по умолчанию join_use_nulls = 0 использует - default-значения типа вместо NULL, что эффективнее.' -preconditions: - syntactic: [] - semantic: [] - data: [] -proof: '' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: '' -example_after: '' -expected_speedup: - estimate: null - measurement_method: 'N/A — environment rule, effect зависит от workload, hardware - и текущих settings.' -risks: -- При join_use_nulls=0 внешний JOIN возвращает default value (0/'') вместо NULL — могут нарушиться ожидания клиентов -- Изменение setting влияет на все запросы с LEFT/RIGHT/FULL JOIN в сессии -opt_in: false -references: -- https://clickhouse.com/docs/best-practices/minimize-optimize-joins -hardware_preconditions: [] -config_preconditions: -- join_use_nulls = 1 (включён в профиле или сессии) -workload_preconditions: -- Запросы активно используют LEFT/RIGHT/FULL JOIN -recommendation: - setting: join_use_nulls - current_value_check: 'SELECT value FROM system.settings WHERE name = ''join_use_nulls''' - recommended_formula: 'join_use_nulls = 0 (default). Использовать join_use_nulls=1 - только при необходимости соответствия ANSI NULL-семантике в outer join.' - example: 'SET join_use_nulls = 0;' -reasoning: 'join_use_nulls=1 оборачивает колонки результата в Nullable, - добавляя дополнительный файл маски null и overhead при ANY-операциях. - join_use_nulls=0 использует default-значение (0 для числовых, пустую строку - для String), что устраняет Nullable-overhead.' -condition: '' diff --git a/docs/rules/cards/E-013-async_insert_busy_timeout_tuning.yaml b/docs/rules/cards/E-013-async_insert_busy_timeout_tuning.yaml deleted file mode 100644 index cbab1ee1..00000000 --- a/docs/rules/cards/E-013-async_insert_busy_timeout_tuning.yaml +++ /dev/null @@ -1,47 +0,0 @@ -id: E-013 -name: async_insert_busy_timeout_tuning -tier: env -category: insert_settings -status: proposed -statement: 'При использовании async_insert=1 параметр async_insert_busy_timeout_ms - (default 200ms на OSS, 1000ms на Cloud) определяет максимальное время ожидания - до flush буфера. Слишком низкое значение ведёт к частым мелким flush, - слишком высокое — к задержке видимости данных.' -preconditions: - syntactic: [] - semantic: [] - data: [] -proof: '' -ch_version: - introduced: '22.6' - deprecated: null - last_validated: '25.3' -example_before: '' -example_after: '' -expected_speedup: - estimate: null - measurement_method: 'N/A — environment rule, effect зависит от workload, hardware - и текущих settings.' -risks: -- Увеличение timeout задерживает видимость свежих данных для SELECT -- Уменьшение timeout увеличивает количество мелких parts и нагрузку на merge -opt_in: false -references: -- https://clickhouse.com/docs/optimize/asynchronous-inserts -- https://clickhouse.com/docs/best-practices/selecting-an-insert-strategy -hardware_preconditions: [] -config_preconditions: -- async_insert = 1 включён -workload_preconditions: -- Ingestion-нагрузка из многих параллельных мелких INSERT-запросов -recommendation: - setting: async_insert_busy_timeout_ms - current_value_check: 'SELECT value FROM system.settings WHERE name = ''async_insert_busy_timeout_ms''' - recommended_formula: '200-1000ms для большинства workload. - При observability (logs/traces) — 1000ms для меньшего числа parts. - При OLTP-подобных workload — 200ms для свежести данных.' - example: 'SET async_insert_busy_timeout_ms = 1000;' -reasoning: 'Flush по таймауту объединяет мелкие INSERT в один part. - Баланс между свежестью данных и количеством parts: больший timeout = меньше - parts = меньше merge-нагрузки, но свежесть данных хуже.' -condition: 'async_insert = 1 активен' diff --git a/docs/rules/cards/E-014-merge_max_bytes_for_level.yaml b/docs/rules/cards/E-014-merge_max_bytes_for_level.yaml deleted file mode 100644 index dd18ed3a..00000000 --- a/docs/rules/cards/E-014-merge_max_bytes_for_level.yaml +++ /dev/null @@ -1,47 +0,0 @@ -id: E-014 -name: merge_max_bytes_for_level -tier: env -category: merge_settings -status: proposed -statement: 'max_bytes_to_merge_at_max_space_in_pool (default ~150GB) определяет - максимальный размер одного слияния при достаточном свободном месте. При - объектном хранилище (S3/GCS) это значение может быть ограничено пропускной - способностью сети; при локальных NVMe его можно увеличить.' -preconditions: - syntactic: [] - semantic: [] - data: [] -proof: '' -ch_version: - introduced: '10.1016' - deprecated: null - last_validated: '25.3' -example_before: '' -example_after: '' -expected_speedup: - estimate: null - measurement_method: 'N/A — environment rule, effect зависит от workload, hardware - и текущих settings.' -risks: -- Увеличение лимита ускоряет конвергенцию к меньшему числу parts, но требует больше RAM и CPU на слияние -- Не влияет на OPTIMIZE FINAL (который игнорирует этот лимит) -opt_in: false -references: -- https://clickhouse.com/docs/operations/settings/merge-tree-settings -hardware_preconditions: -- Объём свободного дискового пространства > 2x от max_bytes_to_merge_at_max_space_in_pool -config_preconditions: [] -workload_preconditions: -- Высокая скорость ingestion приводит к накоплению мелких parts -recommendation: - setting: max_bytes_to_merge_at_max_space_in_pool - current_value_check: 'SELECT value FROM system.merge_tree_settings WHERE name = - ''max_bytes_to_merge_at_max_space_in_pool''' - recommended_formula: '150GB (default) для большинства случаев. До 300-500GB - для локального NVMe при высоком write-throughput.' - example: "-- В SETTINGS CREATE TABLE или в merge_tree секции config.xml:\nmax_bytes_to_merge_at_max_space_in_pool\ - \ = 161061273600 -- 150 GiB default" -reasoning: 'Большие слияния сокращают number of parts быстрее, что улучшает - производительность SELECT. Ограничено пропускной способностью I/O: на SSD - лимит можно поднять, на S3 — лучше оставить стандартным.' -condition: 'system.parts_columns WHERE active = 1 AND bytes > 10GB' diff --git a/docs/rules/cards/R-021-datetime64_zero_to_datetime.yaml b/docs/rules/cards/R-021-datetime64_zero_to_datetime.yaml deleted file mode 100644 index 3c584133..00000000 --- a/docs/rules/cards/R-021-datetime64_zero_to_datetime.yaml +++ /dev/null @@ -1,43 +0,0 @@ -id: R-021 -name: datetime64_zero_to_datetime -tier: 1A -category: schema_types -status: proposed -statement: 'Колонка объявлена как DateTime64(0), что семантически эквивалентно - DateTime — оба хранят время с точностью до секунды. DateTime занимает 4 байта - (UInt32 epoch), DateTime64(0) — 8 байт (Int64). Замена сокращает хранение вдвое - для этой колонки.' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - Колонка объявлена с типом DateTime64(0) или DateTime64(0, timezone) - semantic: [] - data: [] - user: [] -proof: 'DateTime64(0) хранит эпох-секунды как Int64 (8 байт). DateTime хранит - эпох-секунды как UInt32 (4 байта). При precision=0 семантика полностью совпадает - в диапазоне дат DateTime (1970-2106). Разница только в диапазоне: DateTime64 - поддерживает более широкий диапазон дат.' -explain_template: 'Колонка {column} объявлена как DateTime64(0), что идентично - DateTime по точности. DateTime занимает вдвое меньше памяти (4 байта vs 8 байт). - Замените тип на DateTime для экономии хранилища и улучшения производительности - GROUP BY и сортировки.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE events (\n ts DateTime64(0),\n user_id UInt64\n)\ - \ ENGINE = MergeTree ORDER BY ts" -example_after: "CREATE TABLE events (\n ts DateTime,\n user_id UInt64\n) ENGINE\ - \ = MergeTree ORDER BY ts" -expected_speedup: - estimate: '~50% compression для колонки timestamp' - measurement_method: 'Сравнение compressed_bytes по колонке в system.parts_columns - до и после замены типа.' -risks: -- DateTime поддерживает диапазон 1970-01-01 — 2106-02-07; DateTime64(0) шире -- При репликации между разными версиями CH возможна несовместимость типов -opt_in: false -references: -- https://clickhouse.com/docs/best-practices/select-data-types -- https://clickhouse.com/docs/sql-reference/data-types/datetime64 diff --git a/docs/rules/cards/R-022-float_monetary_column_to_decimal.yaml b/docs/rules/cards/R-022-float_monetary_column_to_decimal.yaml deleted file mode 100644 index 169b06af..00000000 --- a/docs/rules/cards/R-022-float_monetary_column_to_decimal.yaml +++ /dev/null @@ -1,45 +0,0 @@ -id: R-022 -name: float_monetary_column_to_decimal -tier: 1B -category: schema_types -status: proposed -statement: 'Колонка объявлена как Float32 или Float64, но имя указывает на - монетарное значение (amount, price, cost, revenue, fee, total, balance, tax). - Float-арифметика не ассоциативна и даёт неточные результаты для денежных сумм. - Рекомендуется Decimal(p, s).' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - Колонка объявлена с типом Float32 или Float64 - - Имя колонки содержит паттерн монетарного домена - semantic: [] - data: [] - user: - - Проверить реальный диапазон и нужную точность перед заменой -proof: 'Float-арифметика не ассоциативна: (a + b) - a != b при больших разницах - в порядке. Для финансовых данных это недопустимо. Decimal(p, s) даёт точные - целочисленные вычисления со смещённой точкой.' -explain_template: 'Колонка {column} объявлена как {col_type}, но по имени - предположительно хранит денежные значения. Float не подходит для финансовых - расчётов из-за ошибок округления. Используйте Decimal32(2) для сумм до ~21M - или Decimal64(2) для больших значений.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE orders (\n order_id UInt64,\n total_amount Float64,\n\ - \ tax_amount Float64\n) ENGINE = MergeTree ORDER BY order_id" -example_after: "CREATE TABLE orders (\n order_id UInt64,\n total_amount Decimal64(2),\n\ - \ tax_amount Decimal64(2)\n) ENGINE = MergeTree ORDER BY order_id" -expected_speedup: - estimate: null - measurement_method: 'Сравнение точности агрегации SUM() по Float64 и Decimal64(2) - на реальных данных.' -risks: -- Decimal ограничен по диапазону (Decimal32 до ~21M, Decimal64 до ~9.2 * 10^16) -- Decimal не поддерживает NaN и Infinity -- Конвертация требует перезаливки данных -opt_in: true -references: -- https://kb.altinity.com/altinity-kb-schema-design/floats-vs-decimals/ -- https://clickhouse.com/docs/best-practices/select-data-types diff --git a/docs/rules/cards/R-023-string_datetime_column_to_date.yaml b/docs/rules/cards/R-023-string_datetime_column_to_date.yaml deleted file mode 100644 index a79ab978..00000000 --- a/docs/rules/cards/R-023-string_datetime_column_to_date.yaml +++ /dev/null @@ -1,43 +0,0 @@ -id: R-023 -name: string_datetime_column_to_date -tier: 1B -category: schema_types -status: proposed -statement: 'Колонка объявлена как String, но имя указывает на дату или время - (date, datetime, timestamp, created_at, updated_at, event_time, event_date, - occurred_at). Хранение дат как String лишает возможности использовать - date-функции напрямую, индексацию по дате и сжатие Delta-кодеком.' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - Колонка объявлена с типом String - - Имя колонки содержит паттерн даты/времени - semantic: [] - data: [] - user: - - Проверить реальный формат дат в данных перед заменой -proof: 'String хранит дату как UTF-8 текст (~10-19 байт). Date хранит как UInt16 - (2 байта). DateTime хранит как UInt32 (4 байта). Числовые типы дат сжимаются - кодеком Delta намного лучше, чем строки.' -explain_template: 'Колонка {column} объявлена как String, но по имени предположительно - хранит дату или время. Это препятствует использованию date-функций без явного - toDate()/toDateTime(), исключает Delta-сжатие и замедляет диапазонные фильтры. - Используйте Date или DateTime.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE events (\n event_id UInt64,\n created_at String,\n\ - \ event_date String\n) ENGINE = MergeTree ORDER BY event_id" -example_after: "CREATE TABLE events (\n event_id UInt64,\n created_at DateTime,\n\ - \ event_date Date\n) ENGINE = MergeTree ORDER BY (event_date, event_id)" -expected_speedup: - estimate: '3-5x сжатие для колонки дат' - measurement_method: 'Сравнение data_compressed_bytes в system.parts_columns.' -risks: -- Требует валидации формата строк в данных перед конвертацией -- Строки вида '2024-01-01 00:00:00.000' требуют уточнения точности (DateTime vs DateTime64) -opt_in: true -references: -- https://clickhouse.com/docs/best-practices/select-data-types -- https://clickhouse.com/docs/sql-reference/data-types/datetime diff --git a/docs/rules/cards/R-024-string_ip_column_to_ipv4.yaml b/docs/rules/cards/R-024-string_ip_column_to_ipv4.yaml deleted file mode 100644 index 7cac4dd0..00000000 --- a/docs/rules/cards/R-024-string_ip_column_to_ipv4.yaml +++ /dev/null @@ -1,42 +0,0 @@ -id: R-024 -name: string_ip_column_to_ipv4 -tier: 1B -category: schema_types -status: proposed -statement: 'Колонка объявлена как String, но имя указывает на IP-адрес - (ip, ip_address, remote_addr, client_ip, server_ip, src_ip, dst_ip, remote_host). - Тип IPv4 хранит адрес в 4 байтах (UInt32) вместо ~15 байт строки и поддерживает - нативные IP-функции (IPv4CIDRToRange, toIPv4 и др.).' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - Колонка объявлена с типом String - - Имя колонки содержит паттерн IP-адреса - semantic: [] - data: [] - user: - - Проверить реальный формат IP-адресов (IPv4, IPv6 или смешанный) -proof: 'IPv4 тип хранит адрес как UInt32 (4 байта). Строка '192.168.1.1' - занимает 11 байт + overhead. Экономия ~4x плюс нативная поддержка CIDR-фильтрации.' -explain_template: 'Колонка {column} объявлена как String, но по имени предположительно - хранит IP-адрес. Тип IPv4 экономит ~4x памяти, поддерживает нативные функции - IPv4NumToString/toIPv4/IPv4CIDRToRange и сортируется корректно для числовой - семантики адресов. Для IPv6 используйте тип IPv6.' -ch_version: - introduced: '116.253' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE access_log (\n request_id UInt64,\n client_ip String,\n\ - \ remote_addr String\n) ENGINE = MergeTree ORDER BY request_id" -example_after: "CREATE TABLE access_log (\n request_id UInt64,\n client_ip IPv4,\n\ - \ remote_addr IPv4\n) ENGINE = MergeTree ORDER BY request_id" -expected_speedup: - estimate: '~4x сжатие для колонки IP' - measurement_method: 'Сравнение data_compressed_bytes в system.parts_columns.' -risks: -- IPv6-адреса не поместятся в IPv4 (нужен IPv6 или String) -- Смешанные форматы (IPv4-mapped IPv6) требуют дополнительной обработки -opt_in: true -references: -- https://kb.altinity.com/altinity-kb-schema-design/how-to-store-ips/ -- https://clickhouse.com/docs/sql-reference/data-types/ipv4 diff --git a/docs/rules/cards/R-025-order_by_tuple_no_pk.yaml b/docs/rules/cards/R-025-order_by_tuple_no_pk.yaml deleted file mode 100644 index fcd2ab89..00000000 --- a/docs/rules/cards/R-025-order_by_tuple_no_pk.yaml +++ /dev/null @@ -1,42 +0,0 @@ -id: R-025 -name: order_by_tuple_no_pk -tier: 1B -category: schema_design -status: proposed -statement: 'CREATE TABLE с явным ORDER BY tuple() означает отсутствие первичного - ключа. Без primary key каждый SELECT выполняет полный скан таблицы — sparse - index недоступен. Для аналитических запросов с фильтрацией это ведёт к - многократно избыточному чтению с диска.' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - DDL содержит ORDER BY tuple() - semantic: [] - data: [] - user: - - Требуется анализ паттернов запросов для выбора правильного ORDER BY -proof: 'ClickHouse хранит данные, отсортированные по ORDER BY-ключу, и строит - sparse primary index по этому ключу. ORDER BY tuple() отключает сортировку - и sparse index, гарантируя полный скан при каждом SELECT с WHERE.' -explain_template: 'Таблица создаётся без первичного ключа (ORDER BY tuple()). - Каждый SELECT будет сканировать все данные. Выберите ORDER BY по колонкам, - наиболее часто используемым в WHERE-условиях, например ORDER BY (user_id, - event_date).' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE events (\n user_id UInt64,\n event_type String,\n\ - \ ts DateTime\n) ENGINE = MergeTree ORDER BY tuple()" -example_after: "CREATE TABLE events (\n user_id UInt64,\n event_type String,\n\ - \ ts DateTime\n) ENGINE = MergeTree ORDER BY (user_id, ts)" -expected_speedup: - estimate: '10-1000x для selective queries' - measurement_method: 'Сравнение read_rows в system.query_log до и после добавления ORDER BY.' -risks: -- Изменение ORDER BY требует пересоздания и перезаливки таблицы -- Неправильный выбор ORDER BY может замедлить INSERT (сортировка данных при вставке) -opt_in: true -references: -- https://clickhouse.com/docs/best-practices/choosing-a-primary-key -- https://clickhouse.com/docs/blog/ai-generated-clickhouse-schemas-mistakes-and-advice diff --git a/docs/rules/cards/R-026-sum_case_to_countif.yaml b/docs/rules/cards/R-026-sum_case_to_countif.yaml deleted file mode 100644 index 962ccabb..00000000 --- a/docs/rules/cards/R-026-sum_case_to_countif.yaml +++ /dev/null @@ -1,35 +0,0 @@ -id: R-026 -name: sum_case_to_countif -tier: 1A -category: aggregate_rewrite -status: proposed -statement: 'SUM(CASE WHEN cond THEN 1 ELSE 0 END) или COUNT(CASE WHEN cond THEN - 1 END) эквивалентны countIf(cond). countIf — встроенный комбинатор ClickHouse, - работает без материализации промежуточного CASE-выражения.' -preconditions: - syntactic: - - Запрос содержит SUM(CASE WHEN ... THEN 1 ELSE 0 END) или COUNT(CASE WHEN ... THEN 1 END) - semantic: [] - data: [] - user: [] -proof: 'countIf(cond) — синтаксический сахар поверх count() с суффиксом -If, - семантически идентичен COUNT(CASE WHEN cond THEN 1 END). ClickHouse выполняет - countIf без создания временного Int8-столбца результата CASE.' -explain_template: 'SUM(CASE WHEN ... THEN 1 ELSE 0 END) в позиции агрегации - заменяется более читаемым и эффективным countIf(cond). Код проще и не требует - материализации промежуточного CASE-результата.' -ch_version: - introduced: '1.23' - deprecated: null - last_validated: '25.3' -example_before: "SELECT\n SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) AS\ - \ active_cnt,\n COUNT(CASE WHEN score > 90 THEN 1 END) AS high_scorers\nFROM users" -example_after: "SELECT\n countIf(status = 'active') AS active_cnt,\n countIf(score\ - \ > 90) AS high_scorers\nFROM users" -expected_speedup: - estimate: '5-10% на больших наборах данных' - measurement_method: 'EXPLAIN PIPELINE до и после; сравнение elapsed в system.query_log.' -risks: [] -opt_in: false -references: -- https://clickhouse.com/docs/sql-reference/aggregate-functions/combinators diff --git a/docs/rules/cards/R-027-sum_case_col_to_sumif.yaml b/docs/rules/cards/R-027-sum_case_col_to_sumif.yaml deleted file mode 100644 index 600e4839..00000000 --- a/docs/rules/cards/R-027-sum_case_col_to_sumif.yaml +++ /dev/null @@ -1,36 +0,0 @@ -id: R-027 -name: sum_case_col_to_sumif -tier: 1A -category: aggregate_rewrite -status: proposed -statement: 'SUM(CASE WHEN cond THEN col ELSE 0 END) семантически эквивалентно - sumIf(col, cond). sumIf — встроенный комбинатор ClickHouse, не требует - материализации CASE-выражения в промежуточный столбец.' -preconditions: - syntactic: - - Запрос содержит SUM(CASE WHEN ... THEN ELSE 0 END) - semantic: - - ELSE-ветка возвращает 0 (или эквивалент нуля) - data: [] - user: [] -proof: 'sumIf(col, cond) применяет сложение только к строкам, где cond=true, - эквивалентно SUM(CASE WHEN cond THEN col ELSE 0 END). При ELSE 0 результаты - математически идентичны, так как 0 нейтрален в сложении.' -explain_template: 'SUM(CASE WHEN {cond} THEN {col} ELSE 0 END) заменяется - sumIf({col}, {cond}). Это устраняет промежуточное CASE-вычисление и делает - код более читаемым.' -ch_version: - introduced: '1.23' - deprecated: null - last_validated: '25.3' -example_before: "SELECT\n SUM(CASE WHEN is_paid THEN amount ELSE 0 END) AS paid_total\n\ - FROM orders" -example_after: "SELECT\n sumIf(amount, is_paid) AS paid_total\nFROM orders" -expected_speedup: - estimate: '5-10% на больших наборах данных' - measurement_method: 'Сравнение elapsed в system.query_log.' -risks: -- Если ELSE-ветка не 0 (например, ELSE -1), замена нарушает семантику -opt_in: false -references: -- https://clickhouse.com/docs/sql-reference/aggregate-functions/combinators diff --git a/docs/rules/cards/R-028-coalesce_two_args_to_ifnull.yaml b/docs/rules/cards/R-028-coalesce_two_args_to_ifnull.yaml deleted file mode 100644 index b5b34947..00000000 --- a/docs/rules/cards/R-028-coalesce_two_args_to_ifnull.yaml +++ /dev/null @@ -1,32 +0,0 @@ -id: R-028 -name: coalesce_two_args_to_ifnull -tier: 1A -category: function_rewrite -status: proposed -statement: 'COALESCE(x, y) с ровно двумя аргументами полностью эквивалентен - ifNull(x, y). ifNull — встроенная функция ClickHouse, которая компилируется - более эффективно и не требует перебора переменного числа аргументов.' -preconditions: - syntactic: - - Запрос содержит COALESCE( с ровно двумя аргументами - semantic: [] - data: [] - user: [] -proof: 'COALESCE(x, y) = первый не-NULL из x, y = ifNull(x, y) при двух - аргументах. Это математически идентично. ifNull — специализированная - функция без overhead перебора varargs.' -explain_template: 'COALESCE({x}, {y}) с двумя аргументами заменяется ifNull({x}, {y}). - Семантика идентична, ifNull компилируется без overhead varargs-перебора.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "SELECT COALESCE(user_name, 'anonymous') AS name FROM users" -example_after: "SELECT ifNull(user_name, 'anonymous') AS name FROM users" -expected_speedup: - estimate: null - measurement_method: 'Минимальный эффект; основное преимущество — читаемость и совместимость с типом.' -risks: [] -opt_in: false -references: -- https://clickhouse.com/docs/sql-reference/functions/functions-for-nulls diff --git a/docs/rules/cards/R-029-lower_col_like_to_ilike.yaml b/docs/rules/cards/R-029-lower_col_like_to_ilike.yaml deleted file mode 100644 index 99273572..00000000 --- a/docs/rules/cards/R-029-lower_col_like_to_ilike.yaml +++ /dev/null @@ -1,36 +0,0 @@ -id: R-029 -name: lower_col_like_to_ilike -tier: 1A -category: function_rewrite -status: proposed -statement: 'lower(col) LIKE pattern семантически эквивалентен col ILIKE pattern. - ILIKE — нативный оператор ClickHouse (с версии 22.6), который выполняет - регистронезависимое сравнение без явного вызова lower(), что упрощает - код и потенциально позволяет оптимизатору использовать skip-индексы.' -preconditions: - syntactic: - - Запрос содержит lower(col) LIKE pattern - semantic: [] - data: [] - user: [] -proof: 'ILIKE(col, pat) в ClickHouse применяет lower() к обоим операндам перед - сравнением, поэтому lower(col) LIKE lower_pat === col ILIKE pat для ASCII-символов. - Паттерн lower(col) LIKE требует двух операций (вызов lower + LIKE), ILIKE — одной.' -explain_template: 'lower({col}) LIKE ''{pattern}'' заменяется {col} ILIKE ''{pattern}''. - Оба выражения регистронезависимы. ILIKE — нативный оператор, не требующий - явной конвертации к lowercase.' -ch_version: - introduced: '22.6' - deprecated: null - last_validated: '25.3' -example_before: "SELECT * FROM logs WHERE lower(message) LIKE '%error%'" -example_after: "SELECT * FROM logs WHERE message ILIKE '%error%'" -expected_speedup: - estimate: null - measurement_method: 'Упрощение плана запроса; реальное ускорение зависит от наличия text-индекса.' -risks: -- ILIKE доступен только начиная с CH 22.6 -- Для non-ASCII символов поведение lower() и ILIKE может различаться в зависимости от locale -opt_in: false -references: -- https://clickhouse.com/docs/sql-reference/functions/string-search-functions diff --git a/docs/rules/cards/R-030-not_in_singleton_to_not_equal.yaml b/docs/rules/cards/R-030-not_in_singleton_to_not_equal.yaml deleted file mode 100644 index b032d46e..00000000 --- a/docs/rules/cards/R-030-not_in_singleton_to_not_equal.yaml +++ /dev/null @@ -1,35 +0,0 @@ -id: R-030 -name: not_in_singleton_to_not_equal -tier: 1A -category: predicate_rewrite -status: proposed -statement: 'x NOT IN (single_value) семантически эквивалентен x != single_value - для не-Nullable колонок. NOT IN с одним элементом строит hash set из одного - значения, тогда как != — прямое скалярное сравнение без накладных расходов - на построение set.' -preconditions: - syntactic: - - WHERE содержит NOT IN с ровно одним литеральным значением - semantic: - - Колонка не Nullable (NULL NOT IN (x) возвращает NULL, а не TRUE) - data: [] - user: [] -proof: 'Для не-Nullable x: x NOT IN (c) ≡ x != c по стандарту SQL. - При одном элементе IN-оператор строит hash set O(1) вместо O(1) сравнения, - что излишне. ClickHouse optimizer не всегда упрощает это автоматически.' -explain_template: '{col} NOT IN ({val}) заменяется {col} != {val}. - Семантика идентична для не-Nullable колонок, запрос становится проще.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "SELECT * FROM events WHERE status NOT IN ('deleted')" -example_after: "SELECT * FROM events WHERE status != 'deleted'" -expected_speedup: - estimate: null - measurement_method: 'Минимальный эффект; преимущество — читаемость и простота плана запроса.' -risks: -- Для Nullable колонок семантика различается (NULL != x возвращает NULL, а не TRUE) -opt_in: false -references: -- https://clickhouse.com/docs/sql-reference/operators/in diff --git a/docs/rules/cards/R-031-string_uuid_column_to_uuid_type.yaml b/docs/rules/cards/R-031-string_uuid_column_to_uuid_type.yaml deleted file mode 100644 index 244d6fea..00000000 --- a/docs/rules/cards/R-031-string_uuid_column_to_uuid_type.yaml +++ /dev/null @@ -1,42 +0,0 @@ -id: R-031 -name: string_uuid_column_to_uuid_type -tier: 1B -category: schema_types -status: proposed -statement: 'Колонка объявлена как String, но имя указывает на UUID (uuid, guid, - trace_id, span_id, request_id). UUID-тип хранит идентификатор в 16 байтах - vs ~36 байт строки с дефисами, и поддерживает нативные UUID-функции.' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - Колонка объявлена с типом String - - Имя колонки указывает на UUID-домен - semantic: [] - data: [] - user: - - Проверить реальный формат значений (должны быть валидные UUIDs) -proof: 'UUID хранит 128 бит (16 байт) в бинарном виде. String UUID - '61f0c404-5cb3-11e7-907b-a6006ad3dba0' занимает 36 байт. Экономия ~2.25x - плюс нативная поддержка generateUUIDv4(), UUIDStringToNum(), toUUID().' -explain_template: 'Колонка {column} объявлена как String, но по имени предположительно - хранит UUID. Тип UUID занимает 16 байт вместо ~36, поддерживает нативные - UUID-функции и корректно сортируется. Примечание: UUIDv7 сортируется по - второй половине в ClickHouse, что может влиять на PRIMARY KEY.' -ch_version: - introduced: '1.0' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE spans (\n trace_id String,\n span_id String,\n ts\ - \ DateTime\n) ENGINE = MergeTree ORDER BY ts" -example_after: "CREATE TABLE spans (\n trace_id UUID,\n span_id UUID,\n ts\ - \ DateTime\n) ENGINE = MergeTree ORDER BY ts" -expected_speedup: - estimate: '~2x сжатие для UUID-колонок' - measurement_method: 'Сравнение data_compressed_bytes в system.parts_columns.' -risks: -- UUIDv7 в PRIMARY KEY даёт неоптимальную сортировку из-за особенности хранения в CH -- Требует изменения INSERT-логики клиента (вставка UUID вместо строки) -opt_in: true -references: -- https://clickhouse.com/docs/sql-reference/data-types/uuid -- https://clickhouse.com/docs/best-practices/select-data-types diff --git a/docs/rules/cards/R-032-int8_boolean_column_to_bool.yaml b/docs/rules/cards/R-032-int8_boolean_column_to_bool.yaml deleted file mode 100644 index d4a3dff4..00000000 --- a/docs/rules/cards/R-032-int8_boolean_column_to_bool.yaml +++ /dev/null @@ -1,42 +0,0 @@ -id: R-032 -name: int8_boolean_column_to_bool -tier: 1B -category: schema_types -status: proposed -statement: 'Колонка объявлена как UInt8 или Int8, но имя указывает на булево - значение (is_*, has_*, flag, enabled, active, deleted, published, visible). - Тип Bool хранится как UInt8 (те же 1 байт), но выводится как true/false, - обеспечивает самодокументирование схемы и проверку допустимых значений.' -preconditions: - syntactic: - - DDL содержит CREATE TABLE - - Колонка объявлена с типом UInt8 или Int8 - - Имя колонки указывает на булев домен - semantic: [] - data: [] - user: - - Убедиться, что значения только 0 и 1 (Bool отклоняет другие значения при строгом режиме) -proof: 'Bool тип в ClickHouse хранится как UInt8 (1 байт). Замена UInt8 на - Bool не меняет хранение, но добавляет семантическую ясность и совместимость - с клиентами, ожидающими boolean-тип.' -explain_template: 'Колонка {column} объявлена как {col_type}, но по имени - предположительно хранит булево значение. Замените на Bool для явного - документирования домена. Хранение идентично UInt8 (1 байт).' -ch_version: - introduced: '22.1' - deprecated: null - last_validated: '25.3' -example_before: "CREATE TABLE users (\n user_id UInt64,\n is_active UInt8,\n has_subscription\ - \ Int8\n) ENGINE = MergeTree ORDER BY user_id" -example_after: "CREATE TABLE users (\n user_id UInt64,\n is_active Bool,\n has_subscription\ - \ Bool\n) ENGINE = MergeTree ORDER BY user_id" -expected_speedup: - estimate: null - measurement_method: 'N/A — изменение семантики, не производительности.' -risks: -- Bool отклоняет значения кроме 0 и 1 при включённом strict_types -- Требует CH >= 22.1 -opt_in: true -references: -- https://clickhouse.com/docs/sql-reference/data-types/boolean -- https://clickhouse.com/docs/best-practices/select-data-types diff --git a/scripts/ml/__init__.py b/scripts/ml/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/ml/extract_dataset_features.py b/scripts/ml/extract_dataset_features.py deleted file mode 100644 index 339dbe4b..00000000 --- a/scripts/ml/extract_dataset_features.py +++ /dev/null @@ -1,107 +0,0 @@ -"""Extract QueryFeatures from all synthetic_expanded benchmark cases and save to JSONL. - -Output format (one JSON object per line): -{ - "case_id": "synthetic_expanded_r001_001", - "features": {"has_count_distinct": 1, ...}, - "labels": ["exact_count_distinct_specialization", "approx_count_distinct_advisory"], - "split": "train" -} - -Labels come from known_issues[].type (semantic problem-type labels, not rule IDs). -Split assignment comes from benchmark/splits/synthetic_expanded_v1.yaml. -Negative cases have labels=[]. -""" -from __future__ import annotations - -import json -import sys -from pathlib import Path - -import yaml - -REPO_ROOT = Path(__file__).resolve().parents[2] -sys.path.insert(0, str(REPO_ROOT)) - -from clickadvisor.ml.features import FeatureExtractor # noqa: E402 - -CASES_DIR = REPO_ROOT / "benchmark" / "cases" / "synthetic_expanded" -SPLIT_PATH = REPO_ROOT / "benchmark" / "splits" / "synthetic_expanded_v1.yaml" -OUTPUT_PATH = REPO_ROOT / "data" / "ml" / "features_dataset.jsonl" - - -def load_split(split_path: Path) -> dict[str, str]: - """Return {case_id: "train"|"test"} mapping.""" - payload = yaml.safe_load(split_path.read_text(encoding="utf-8")) - mapping: dict[str, str] = {} - for case_id in payload.get("train_case_ids", []): - mapping[case_id] = "train" - for case_id in payload.get("test_case_ids", []): - mapping[case_id] = "test" - return mapping - - -def main() -> None: - extractor = FeatureExtractor() - split_map = load_split(SPLIT_PATH) - - case_files = sorted(CASES_DIR.glob("*.yaml")) - if not case_files: - print(f"No YAML files found in {CASES_DIR}", file=sys.stderr) - sys.exit(1) - - OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True) - - label_set: set[str] = set() - train_count = 0 - test_count = 0 - skipped = 0 - - with OUTPUT_PATH.open("w", encoding="utf-8") as out: - for path in case_files: - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - if not isinstance(payload, dict): - skipped += 1 - continue - - case_id: str = payload.get("case_id", path.stem) - sql: str = payload.get("sql", "") - if not sql: - skipped += 1 - continue - - known_issues = payload.get("known_issues") or [] - labels: list[str] = [ - issue["type"] - for issue in known_issues - if isinstance(issue, dict) and "type" in issue - ] - label_set.update(labels) - - split = split_map.get(case_id, "unknown") - - features = extractor.extract(sql).to_vector() - - record = { - "case_id": case_id, - "features": features, - "labels": labels, - "split": split, - } - out.write(json.dumps(record, ensure_ascii=False) + "\n") - - if split == "train": - train_count += 1 - elif split == "test": - test_count += 1 - - total = train_count + test_count + skipped - print(f"Written {total} records to {OUTPUT_PATH}") - print(f" train: {train_count}, test: {test_count}, skipped/unknown: {skipped}") - print(f" unique labels ({len(label_set)}):") - for label in sorted(label_set): - print(f" {label}") - - -if __name__ == "__main__": - main() diff --git a/tests/ml/__init__.py b/tests/ml/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/ml/test_features.py b/tests/ml/test_features.py deleted file mode 100644 index 52748391..00000000 --- a/tests/ml/test_features.py +++ /dev/null @@ -1,339 +0,0 @@ -"""Tests for FeatureExtractor using real SQL from synthetic_expanded benchmark. - -Coverage strategy: -- 1 positive test per template (23 templates = 23 tests) -- 3 negative-case tests (no features should fire for clean SQL) -- 2 parse-error resilience tests -""" -from __future__ import annotations - -import logging - -import pytest - -from clickadvisor.ml.features import FeatureExtractor, QueryFeatures - -_fx = FeatureExtractor() - - -def extract(sql: str) -> QueryFeatures: - return _fx.extract(sql) - - -# --------------------------------------------------------------------------- -# R-001 / R-002: exact_count_distinct_specialization + approx_count_distinct -# --------------------------------------------------------------------------- -def test_r001_count_distinct(): - f = extract("SELECT COUNT(DISTINCT user_id) FROM events") - assert f.has_count_distinct is True - - -def test_r001_to_vector_bool_is_int(): - f = extract("SELECT COUNT(DISTINCT user_id) FROM events") - v = f.to_vector() - assert v["has_count_distinct"] == 1 - assert isinstance(v["has_count_distinct"], int) - - -# --------------------------------------------------------------------------- -# R-003: exact_quantile_candidate -# --------------------------------------------------------------------------- -def test_r003_quantile_exact(): - f = extract("SELECT quantileExact(0.95)(response_time) FROM requests") - assert f.has_quantile_exact is True - - -# --------------------------------------------------------------------------- -# R-004: count_star_distinct_subquery -# --------------------------------------------------------------------------- -def test_r004_count_star_distinct_subquery(): - f = extract("SELECT COUNT(*) FROM (SELECT DISTINCT user_id FROM events)") - assert f.has_subquery is True - # COUNT(*) over subquery – no count_distinct at the outer level - assert f.has_count_distinct is False - - -# --------------------------------------------------------------------------- -# R-005: function_on_datetime_filter (toDate equality) -# --------------------------------------------------------------------------- -def test_r005_todate_equality(): - f = extract("SELECT count() FROM events WHERE toDate(created_at) = '2024-01-15'") - assert f.has_function_on_filter_column is True - - -# --------------------------------------------------------------------------- -# R-006: date_part_filter_to_range (toYYYYMM equality) -# --------------------------------------------------------------------------- -def test_r006_toyyyymm_equality(): - f = extract("SELECT count() FROM events WHERE toYYYYMM(event_date) = 202401") - assert f.has_function_on_filter_column is True - - -# --------------------------------------------------------------------------- -# R-007: interval_start_filter_to_range (toStartOfHour equality) -# --------------------------------------------------------------------------- -def test_r007_tostartofhour_equality(): - f = extract("SELECT count() FROM logs WHERE toStartOfHour(ts) = '2024-01-15 14:00:00'") - assert f.has_function_on_filter_column is True - - -# --------------------------------------------------------------------------- -# R-008: redundant_cast_on_filter -# --------------------------------------------------------------------------- -def test_r008_redundant_cast(): - f = extract("SELECT count() FROM users WHERE CAST(user_id AS UInt64) = 12345") - assert f.has_cast is True - assert f.has_function_on_filter_column is True - - -# --------------------------------------------------------------------------- -# R-009: singleton_in_predicate -# --------------------------------------------------------------------------- -def test_r009_singleton_in(): - f = extract("SELECT count() FROM events WHERE country IN ('RU')") - assert f.has_in_with_single_value is True - - -# --------------------------------------------------------------------------- -# R-010: disjunction_chain_to_in -# --------------------------------------------------------------------------- -def test_r010_or_chain(): - f = extract( - "SELECT count() FROM events WHERE country = 'RU' OR country = 'BY' OR country = 'KZ'" - ) - assert f.has_or_chain_same_column is True - - -# --------------------------------------------------------------------------- -# R-011: having_without_aggregate -# --------------------------------------------------------------------------- -def test_r011_having_without_aggregate(): - f = extract( - "SELECT user_id, COUNT(*) FROM events GROUP BY user_id " - "HAVING country = 'RU' AND COUNT(*) > 100" - ) - assert f.has_having is True - assert f.has_having_without_aggregate is True - assert f.has_group_by is True - - -# --------------------------------------------------------------------------- -# R-012: constant_predicate (WHERE TRUE) -# --------------------------------------------------------------------------- -def test_r012_constant_predicate(): - f = extract("SELECT count() FROM events WHERE TRUE AND user_id = 5") - assert f.has_constant_predicate is True - - -# --------------------------------------------------------------------------- -# R-013: length_empty_predicate -# --------------------------------------------------------------------------- -def test_r013_length_zero_check(): - f = extract("SELECT count() FROM comments WHERE length(body) > 0") - assert f.has_length_zero_check is True - - -# --------------------------------------------------------------------------- -# R-014: groupby_string_hash_candidate -# --------------------------------------------------------------------------- -def test_r014_groupby_string_column(): - f = extract("SELECT url, COUNT(*) FROM logs GROUP BY url") - assert f.has_group_by is True - assert f.has_group_by_string_column is True - - -# --------------------------------------------------------------------------- -# R-015: distinct_after_groupby -# --------------------------------------------------------------------------- -def test_r015_distinct_after_groupby(): - f = extract( - "SELECT DISTINCT a, b FROM (SELECT a, b, COUNT(*) AS cnt FROM events GROUP BY a, b) LIMIT 100" - ) - assert f.has_subquery is True - assert f.has_group_by is True - assert f.has_limit is True - - -# --------------------------------------------------------------------------- -# R-016: orderby_without_limit_in_subquery -# --------------------------------------------------------------------------- -def test_r016_orderby_no_limit_subquery(): - f = extract("SELECT COUNT(*) FROM (SELECT * FROM events ORDER BY created_at)") - assert f.has_subquery_with_orderby_no_limit is True - assert f.has_subquery is True - - -# --------------------------------------------------------------------------- -# R-017: subquery_filter_pushdown -# --------------------------------------------------------------------------- -def test_r017_subquery_filter_pushdown(): - f = extract( - "SELECT * FROM (SELECT * FROM events WHERE status = 'active') WHERE user_id = 42" - ) - assert f.has_nested_subquery_filter is True - assert f.has_subquery is True - - -# --------------------------------------------------------------------------- -# R-018: union_without_all -# --------------------------------------------------------------------------- -def test_r018_union_not_all(): - f = extract("SELECT user_id FROM events_2023 UNION SELECT user_id FROM events_2024") - assert f.has_union is True - assert f.has_union_all is False - - -def test_r018_union_all_no_flag(): - f = extract("SELECT user_id FROM events_2023 UNION ALL SELECT user_id FROM events_2024") - assert f.has_union is True - assert f.has_union_all is True - - -# --------------------------------------------------------------------------- -# R-019: oversized_uint_type_narrowing (CREATE TABLE context) -# --------------------------------------------------------------------------- -def test_r019_create_table(): - f = extract( - "CREATE TABLE events (event_type UInt64, user_id UInt64) ENGINE = MergeTree() ORDER BY event_type" - ) - # No SELECT-level features should fire - assert f.has_count_distinct is False - assert f.has_select_star is False - assert f.has_no_limit is False - assert f.query_length_chars > 0 - - -# --------------------------------------------------------------------------- -# R-020: unsafe_cast_without_default -# --------------------------------------------------------------------------- -def test_r020_throwing_cast(): - f = extract("SELECT CAST(raw_value AS UInt32) FROM events") - assert f.has_cast is True - assert f.has_cast_without_default is True - - -def test_r020_safe_cast_ordefault(): - f = extract("SELECT toUInt32OrDefault(raw_value) FROM events") - assert f.has_cast is True - assert f.has_cast_without_default is False - - -# --------------------------------------------------------------------------- -# D-003: select_star_on_wide_table -# --------------------------------------------------------------------------- -def test_d003_select_star(): - f = extract("SELECT * FROM events LIMIT 10") - assert f.has_select_star is True - assert f.has_limit is True - assert f.has_no_limit is False - - -# --------------------------------------------------------------------------- -# D-004: missing_limit_on_unbounded_result -# --------------------------------------------------------------------------- -def test_d004_missing_limit(): - f = extract("SELECT user_id, event_type, created_at FROM events WHERE status = 'active'") - assert f.has_no_limit is True - assert f.has_limit is False - - -# --------------------------------------------------------------------------- -# D-007: final_modifier_usage -# --------------------------------------------------------------------------- -def test_d007_final_modifier(): - f = extract("SELECT count() FROM events FINAL WHERE user_id = 1") - assert f.has_final_modifier is True - - -# --------------------------------------------------------------------------- -# D-014: async_insert_without_wait_flag -# --------------------------------------------------------------------------- -def test_d014_async_insert_no_wait(): - f = extract("INSERT INTO events SETTINGS async_insert=1 VALUES (1, 'click')") - assert f.has_async_insert_setting is True - assert f.has_async_insert_without_wait is True - - -def test_d014_async_insert_with_wait_ok(): - f = extract( - "INSERT INTO events SETTINGS async_insert=1, wait_for_async_insert=1 VALUES (1, 'click')" - ) - assert f.has_async_insert_setting is True - assert f.has_async_insert_without_wait is False - - -# --------------------------------------------------------------------------- -# Negative cases: clean queries should produce all-False features -# --------------------------------------------------------------------------- -def test_negative_simple_count(): - """Simple timestamp-range query – no problematic patterns.""" - sql = ( - "SELECT count() FROM events " - "WHERE created_at >= '2024-01-15 00:00:00' AND created_at < '2024-01-16 00:00:00'" - ) - f = extract(sql) - assert f.has_count_distinct is False - assert f.has_select_star is False - assert f.has_final_modifier is False - assert f.has_function_on_filter_column is False - assert f.has_quantile_exact is False - assert f.has_async_insert_without_wait is False - - -def test_negative_aggregate_no_limit(): - """Aggregate query – missing_limit rule should NOT fire.""" - f = extract("SELECT COUNT(*) FROM events WHERE event_type = 'click'") - assert f.has_no_limit is False - - -def test_negative_union_all_clean(): - """UNION ALL is fine – union_without_all should be False.""" - f = extract("SELECT id FROM a UNION ALL SELECT id FROM b LIMIT 100") - assert f.has_union is True - assert f.has_union_all is True - - -# --------------------------------------------------------------------------- -# Parse error resilience -# --------------------------------------------------------------------------- -def test_parse_error_returns_features(caplog): - """Badly malformed SQL must not raise – fallback path returns QueryFeatures.""" - bad_sql = "SELECT @@@ BROKEN SQL @@@ FROM" - with caplog.at_level(logging.WARNING, logger="clickadvisor.ml.features"): - f = extract(bad_sql) - assert isinstance(f, QueryFeatures) - assert f.query_length_chars == len(bad_sql) - - -def test_parse_error_logs_warning(caplog): - """A warning must be emitted when AST parsing fails.""" - with caplog.at_level(logging.WARNING): - _fx.extract("SELECT FROM WHERE ??? !!!") - assert any("AST parse failed" in r.message for r in caplog.records) - - -# --------------------------------------------------------------------------- -# Numeric fields -# --------------------------------------------------------------------------- -def test_numeric_fields_basic(): - f = extract("SELECT user_id, event_type FROM events WHERE status = 'active'") - assert f.table_count >= 1 - assert f.column_count_in_select == 2 - assert f.query_length_chars > 0 - - -def test_where_clause_depth_increases_with_nesting(): - simple = extract("SELECT count() FROM events WHERE x = 1") - nested = extract( - "SELECT count() FROM events WHERE (a = 1 AND (b = 2 OR (c = 3 AND d = 4)))" - ) - assert nested.where_clause_depth > simple.where_clause_depth - - -def test_to_vector_keys_match_fields(): - """to_vector() must return exactly the same set of field names as the dataclass.""" - import dataclasses - f = extract("SELECT count() FROM events") - vector = f.to_vector() - field_names = {field.name for field in dataclasses.fields(QueryFeatures)} - assert set(vector.keys()) == field_names