Skip to content

fix(substrait): preserve dictionary type in VALUES literals - #27

Open
discord9 wants to merge 3 commits into
GreptimeTeam:greptimedb-53.1.0-function-signature-exec-errorfrom
discord9:fix/substrait-dict-53
Open

fix(substrait): preserve dictionary type in VALUES literals#27
discord9 wants to merge 3 commits into
GreptimeTeam:greptimedb-53.1.0-function-signature-exec-errorfrom
discord9:fix/substrait-dict-53

Conversation

@discord9

Copy link
Copy Markdown

What

Route VALUES rows containing non-null ScalarValue::Dictionary literals through the expression format (VirtualTable.expressions) instead of the deprecated literal-row path (convert_literal_rowsto_substrait_literal), which encoded only the inner scalar and lost the dictionary type.

Why

Follow-up to #26. When a VALUES row contains Dictionary(UInt32, Utf8("a")), the old path emitted only the inner Utf8 literal; after consumption the plan has a dictionary base schema but an inner-typed expression, and RecordBatch::try_new_with_options rejects the mismatch against the dictionary field.

Fix

  • read_rel.rs from_values: detect non-null dictionary literals (alias-unwrapped) and fall back to convert_expression_rows (expression format) for the whole table. Non-dictionary VALUES keep the exact same literal path; null dictionaries still encode as typed Null literals.
  • Fix a compile error in the fix(substrait): support Dictionary literals in producer #26 dictionary literal test (cast.field.data_type()cast.data_type).

Tests

roundtrip_values_with_dictionary: full encode → decode → optimize → execute round-trip asserting the decoded expression is Expr::Cast(inner, Dictionary), both schema and batch column keep the Dictionary type, and execution succeeds (previously rejected). All 6 values tests + 2 dictionary unit tests pass.

Encode ScalarValue::Dictionary as its inner value in
to_substrait_literal. Dictionary type info is carried by the type layer
as a Map with DICTIONARY_MAP_TYPE_VARIATION_REF, so the literal layer
only needs the inner value; null dictionaries are handled by the
is_null() check at the top.

GreptimeDB flow queries against dictionary-encoded PK string columns
(e.g. metric tables) fail with 'Failed to encode DataFusion plan:
NotImplemented("Unsupported literal: Dictionary(UInt32, Utf8(...))")'.
Fixing the producer unblocks all substrait encode paths (flow, dist
plan, TQL) at once.

Also add unit tests for non-null and null dictionary literals.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
…erals (waynexia#25)

Address review feedback: encoding ScalarValue::Dictionary as its bare
inner literal loses the dictionary type in positions without a separate
type layer (projection, VALUES), silently changing the output schema.

Wrap the inner literal in a cast to the dictionary type in
to_substrait_literal_expr so the consumer reconstructs a
Dictionary-typed value. Also add a full expression round-trip test
verifying the type is preserved.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
 follow-up)

Route VALUES rows containing non-null dictionary literals through the
expression format (VirtualTable.expressions) instead of the deprecated
literal-row path, which encoded only the inner scalar and lost the
dictionary type. The consumer decodes the resulting cast back to a
Dictionary-typed expression, so physical planning no longer hits
RecordBatch::try_new_with_options schema mismatch.

Also fix a compile error in the dictionary literal test from waynexia#26
(cast.field.data_type() -> cast.data_type).

Adds roundtrip_values_with_dictionary end-to-end test.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant