Arvid Heise created FLINK-40496:
-----------------------------------

             Summary: CREATE OR ALTER MATERIALIZED TABLE ignores query column 
position, silently producing a schema whose column order disagrees with the 
query (ALTER ... AS is correct)
                 Key: FLINK-40496
                 URL: https://issues.apache.org/jira/browse/FLINK-40496
             Project: Flink
          Issue Type: Bug
          Components: Table SQL / Planner
    Affects Versions: 2.3.0
            Reporter: Arvid Heise
            Assignee: Arvid Heise


h2. What happens

When CREATE OR ALTER evolves a materialized table's query so a column is added 
anywhere but the end of the projection, the stored schema does not follow the 
query's column order: the new column is appended at the end and the 
pre-existing columns keep their positions. ALTER MATERIALIZED TABLE ... AS 
handles the same evolution correctly.

Given mt = (a, b, c, d) from SELECT a, b, c, d FROM t1:

{code:sql}
CREATE OR ALTER MATERIALIZED TABLE mt AS SELECT a, b, c, 42 AS mid, d FROM t1;
{code}

Expected stored schema: (a, b, c, mid, d)  -- the query projection order.
Actual stored schema:   (a, b, c, d, mid)  -- mid appended at the end.

This passes all DDL-time validation, including 
AlterMaterializedTableChangeOperation.validateChanges(); nothing rejects it. 
The mismatch only surfaces later, when the refresh runs a positional INSERT 
INTO mt <expandedQuery> (no column list): query position 4 (mid) binds to 
stored position 4 (d), and planning fails with a sink type mismatch 
(DynamicSinkUtils: "Incompatible types for sink column ... at position ...").

h2. Root cause

The two query-evolution paths use different diff methods, and only one diffs 
column position:

* ALTER ... AS uses MaterializedTableUtils.buildSchemaTableChanges, which 
appends new columns and calls applyPositionChanges for name-matched columns, 
emitting modifyColumnPosition so existing columns flow around the appended one.
* CREATE OR ALTER uses MaterializedTableUtils.validateAndExtractColumnChanges 
(via SqlCreateOrAlterMaterializedTableConverter.getSchemaTableChanges), which 
appends new columns but never diffs position. A comment there states position 
diffing is skipped on the assumption that reorders are handled on the ALTER MT 
AS path; that path is not reached for CREATE OR ALTER.

By the time either method runs, the new schema's column order is the query 
projection order (an explicit DDL column list only overrides types/comments in 
place via MergeTableAsUtil.mergeColumns; the identifier-only form permutes 
exactly the query's columns), so the position must be honored.

h2. Fix

Make CREATE OR ALTER diff column position like ALTER ... AS: in 
validateAndExtractColumnChanges, emit modifyColumnPosition for name-matched 
columns whose index changed. Position each old column by its rank among the 
columns that survive into the new schema, so retained non-persisted columns 
(which CREATE OR ALTER keeps but the query projection omits) do not skew the 
comparison.

With the fix, CREATE OR ALTER matches ALTER ... AS: inserting a column before 
the last column stores the correct order, and an insertion that would reorder 
existing physical columns relative to each other is rejected up front by 
validateChanges (the append-only guard) with a clear error, instead of silently 
miscompiling at refresh time.

h2. Note

Making the refresh INSERT column-name-qualified would avoid the miscompile, but 
the stored schema order would still disagree with the query, so it complements 
rather than replaces this fix.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to