Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logical error 'Unexpected return type from equals' in group_by_use_nulls + GROUPING SETS #60538

Open
vdimir opened this issue Feb 29, 2024 · 6 comments · May be fixed by #63405
Open

Logical error 'Unexpected return type from equals' in group_by_use_nulls + GROUPING SETS #60538

vdimir opened this issue Feb 29, 2024 · 6 comments · May be fixed by #63405
Assignees
Labels
fuzz Problem found by one of the fuzzers testing Special issue with list of bugs found by CI

Comments

@vdimir
Copy link
Member

vdimir commented Feb 29, 2024

https://fiddle.clickhouse.com/dba51b74-4843-46e5-abbc-8cb5d0310373

And it works on latest, though. But broken on head

DROP TABLE IF EXISTS test_grouping_sets_predicate;

CREATE TABLE test_grouping_sets_predicate
(
    day_ Date,
    type_1 String
)
ENGINE=MergeTree
ORDER BY day_;

INSERT INTO test_grouping_sets_predicate SELECT toDate('2023-01-05') AS day_, 'hello, world' FROM numbers (10);

SET group_by_use_nulls = true;

SELECT *
FROM
( SELECT
    day_,
    type_1
FROM test_grouping_sets_predicate
GROUP BY
    GROUPING SETS ( (day_, type_1), (day_) )
)
WHERE day_ = '2023-01-05';
Code: 49. DB::Exception: Received from localhost:9000. DB::Exception: Unexpected return type from equals. Expected Nullable. Got UInt8: while executing 'FUNCTION equals(day_ : 0, '2023-01-05' :: 1) -> equals(day_, '2023-01-05') Nullable(UInt8) : 3'. (LOGICAL_ERROR)
@vdimir vdimir added testing Special issue with list of bugs found by CI fuzz Problem found by one of the fuzzers labels Feb 29, 2024
@antonio2368
Copy link
Member

just a note, it was probably broken before 24.1 but @Algunenano added a check for it which is getting triggered now
#59379

@azat
Copy link
Collaborator

azat commented Mar 12, 2024

@divanik
Copy link
Member

divanik commented Mar 18, 2024

One more - https://s3.amazonaws.com/clickhouse-test-reports/59390/7d38789e3053b6912300e9fd48456cd3b3426690/stress_test__tsan_.html
Also what interesting here is that there is no stack trace in clickhouse-server.stress.log

@Avogar Avogar self-assigned this Mar 18, 2024
@Avogar
Copy link
Member

Avogar commented Mar 20, 2024

The problem here is in filter pushdown:

create table test (x UInt32, y UInt32) engine=MergeTree order by x;
insert into test values (1, 2), (2, 3);

With pushdown:

select * from (select * from test group by grouping sets ((x, y), (y))) where y = 2 settings group_by_use_nulls=1, query_plan_filter_push_down=1;
<Fatal> : Logical error: 'Unexpected return type from equals. Expected Nullable. Got UInt8'

Without pushdown:

select * from (select * from test group by grouping sets ((x, y), (y))) where y = 2 settings group_by_use_nulls=1, query_plan_filter_push_down=0;
┌────x─┬─y─┐
│ ᴺᵁᴸᴸ │ 2 │
└──────┴───┘
┌─x─┬─y─┐
│ 1 │ 2 │
└───┴───┘

Let's see result of explain plan for both:

:) explain plan header=1, actions=1 select * from (select * from test group by grouping sets ((x, y), (y))) where y = 2 settings group_by_use_nulls=1, query_plan_filter_push_down=1;

EXPLAIN header = 1, actions = 1
SELECT *
FROM
(
    SELECT *
    FROM test
    GROUP BY
        GROUPING SETS (
            (x, y),
            (y))
)
WHERE y = 2
SETTINGS group_by_use_nulls = 1, query_plan_filter_push_down = 1

Query id: d3e446c1-8313-492b-9f35-04ef0e2aba28

Execute function equals/equals(y, 2)/Nullable(UInt8)
┌─explain───────────────────────────────────────────────────────────────────────────────┐
│ Expression ((Projection + (Before ORDER BY + )))                                      │
│ Header: x Nullable(UInt32)                                                            │
│         y Nullable(UInt32)                                                            │
│ Actions: INPUT :: 0 -> x Nullable(UInt32) : 0                                         │
│          INPUT :: 1 -> y Nullable(UInt32) : 1                                         │
│ Positions: 0 1                                                                        │
│   Aggregating                                                                         │
│   Header: __grouping_set UInt64                                                       │
│           x Nullable(UInt32)                                                          │
│           y Nullable(UInt32)                                                          │
│   Keys: x, y                                                                          │
│   Skip merging: 0                                                                     │
│     Filter                                                                            │
│     Header: x UInt32                                                                  │
│             y UInt32                                                                  │
│     Filter column: equals(y, 2) (removed)                                             │
│     Actions: INPUT : 1 -> y Nullable(UInt32) : 0                                      │
│              COLUMN Const(UInt8) -> 2 UInt8 : 1                                       │
│              INPUT :: 0 -> x UInt32 : 2                                               │
│              FUNCTION equals(y : 0, 2 :: 1) -> equals(y, 2) Nullable(UInt8) : 3       │
│     Positions: 3 2 0                                                                  │
│       Expression                                                                      │
│       Header: x UInt32                                                                │
│               y UInt32                                                                │
│       Actions: INPUT :: 0 -> x UInt32 : 0                                             │
│                INPUT :: 1 -> y UInt32 : 1                                             │
│       Positions: 0 1                                                                  │
│         ReadFromMergeTree (default.test)                                              │
│         Header: y UInt32                                                              │
│                 x UInt32                                                              │
│         ReadType: Default                                                             │
│         Parts: 1                                                                      │
│         Granules: 1                                                                   │
│         Prewhere info                                                                 │
│         Need filter: 1                                                                │
│           Prewhere filter                                                             │
│           Prewhere filter column: equals(y, 2) (removed)                              │
│           Actions: INPUT : 0 -> y UInt32 : 0                                          │
│                    COLUMN Const(UInt8) -> 2 UInt8 : 1                                 │
│                    FUNCTION equals(y : 0, 2 :: 1) -> equals(y, 2) Nullable(UInt8) : 2 │
│           Positions: 0 2                                                              │
└───────────────────────────────────────────────────────────────────────────────────────┘

:) explain plan header=1, actions=1 select * from (select * from test group by grouping sets ((x, y), (y))) where y = 2 settings group_by_use_nulls=1, query_plan_filter_push_down=0;

EXPLAIN header = 1, actions = 1
SELECT *
FROM
(
    SELECT *
    FROM test
    GROUP BY
        GROUPING SETS (
            (x, y),
            (y))
)
WHERE y = 2
SETTINGS group_by_use_nulls = 1, query_plan_filter_push_down = 0

Query id: 069ea73f-98a0-4b2b-bdb0-a38de0116752

Execute function equals/equals(y, 2)/Nullable(UInt8)
┌─explain─────────────────────────────────────────────────────────────────────────┐
│ Expression ((Projection + Before ORDER BY))                                     │
│ Header: x Nullable(UInt32)                                                      │
│         y Nullable(UInt32)                                                      │
│ Actions: INPUT :: 0 -> x Nullable(UInt32) : 0                                   │
│          INPUT :: 1 -> y Nullable(UInt32) : 1                                   │
│ Positions: 0 1                                                                  │
│   Filter ((WHERE + (Projection + Before ORDER BY)))                             │
│   Header: x Nullable(UInt32)                                                    │
│           y Nullable(UInt32)                                                    │
│   Filter column: equals(y, 2) (removed)                                         │
│   Actions: INPUT :: 0 -> x Nullable(UInt32) : 0                                 │
│            INPUT : 1 -> y Nullable(UInt32) : 1                                  │
│            COLUMN Const(UInt8) -> 2 UInt8 : 2                                   │
│            FUNCTION equals(y : 1, 2 :: 2) -> equals(y, 2) Nullable(UInt8) : 3   │
│   Positions: 0 1 3                                                              │
│     Filter (HAVING)                                                             │
│     Header: x Nullable(UInt32)                                                  │
│             y Nullable(UInt32)                                                  │
│     Filter column: equals(y, 2) (removed)                                       │
│     Actions: INPUT :: 0 -> x Nullable(UInt32) : 0                               │
│              INPUT : 1 -> y Nullable(UInt32) : 1                                │
│              COLUMN Const(UInt8) -> 2 UInt8 : 2                                 │
│              FUNCTION equals(y : 1, 2 :: 2) -> equals(y, 2) Nullable(UInt8) : 3 │
│     Positions: 0 1 3                                                            │
│       Aggregating                                                               │
│       Header: __grouping_set UInt64                                             │
│               x Nullable(UInt32)                                                │
│               y Nullable(UInt32)                                                │
│       Keys: x, y                                                                │
│       Skip merging: 0                                                           │
│         Expression (Before GROUP BY)                                            │
│         Header: x UInt32                                                        │
│                 y UInt32                                                        │
│         Actions: INPUT :: 0 -> x UInt32 : 0                                     │
│                  INPUT :: 1 -> y UInt32 : 1                                     │
│         Positions: 0 1                                                          │
│           ReadFromMergeTree (default.test)                                      │
│           Header: x UInt32                                                      │
│                   y UInt32                                                      │
│           ReadType: Default                                                     │
│           Parts: 1                                                              │
│           Granules: 1                                                           │
└─────────────────────────────────────────────────────────────────────────────────┘

With pushdown we see:

│           Prewhere filter                                                             │
│           Prewhere filter column: equals(y, 2) (removed)                              │
│           Actions: INPUT : 0 -> y UInt32 : 0                                          │
│                    COLUMN Const(UInt8) -> 2 UInt8 : 1                                 │
│                    FUNCTION equals(y : 0, 2 :: 1) -> equals(y, 2) Nullable(UInt8) : 2 │

When we use group_by_use_nulls=1, we make all keys from grouping sets Nullable, but seems like during pushdown we don't check that and as a result, in filter that was pushed down we have non-nullable input column for equals function but expect Nullable result from it.

@Avogar
Copy link
Member

Avogar commented Mar 20, 2024

Let's just disable filter pushdown with grouping sets and group_by_use_nulls=1

@vdimir
Copy link
Member Author

vdimir commented May 6, 2024

In current head reproducer from the first comment returns Illegal column for DataTypeNullable. (ILLEGAL_COLUMN) about __table1.day_ Nullable(Date) UInt16(size = 0) instead of logical error, but still doesn't look correct

UPD: for allow_experimental_analyzer=0 it's still logical error

@vdimir vdimir self-assigned this May 6, 2024
@vdimir vdimir linked a pull request May 6, 2024 that will close this issue
31 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fuzz Problem found by one of the fuzzers testing Special issue with list of bugs found by CI
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants