Skip to content

Fix expression defaults being quoted as string literals#695

Merged
aparajon merged 3 commits into
mainfrom
aparajon/fix-expression-defaults
Apr 20, 2026
Merged

Fix expression defaults being quoted as string literals#695
aparajon merged 3 commits into
mainfrom
aparajon/fix-expression-defaults

Conversation

@aparajon
Copy link
Copy Markdown
Collaborator

@aparajon aparajon commented Apr 20, 2026

What's this?

Fixes expression defaults like json_object(), json_array(), and uuid() being incorrectly quoted as string literals in generated ALTER statements.

Before: ALTER TABLE t1 ADD COLUMN metadata json NOT NULL DEFAULT 'json_object()' (errno 1101)
After: ALTER TABLE t1 ADD COLUMN metadata json NOT NULL DEFAULT (json_object())

How it works

  • Adds DefaultIsExpr bool to the Column struct to track whether a default is an expression vs literal
  • During parsing, inspects the TiDB AST node: non-timestamp FuncCallExpr nodes (json_object, json_array, uuid, etc.) are flagged as expression defaults
  • formatColumnDefinition uses DEFAULT (expr) for expression defaults instead of DEFAULT 'expr'
  • Also fixes parseExpression stripping () from all zero-arg functions — now only strips for timestamp-family functions where MySQL's canonical form omits parens

Most of this was written by Claude Code — I just provided direction.

aparajon and others added 3 commits April 20, 2026 17:00
…as string literals

The schema differ was incorrectly quoting expression defaults like
json_object() and json_array() as string literals (e.g. DEFAULT 'json_object()')
instead of wrapping them in parentheses (DEFAULT (json_object())). This caused
MySQL to reject the generated ALTER with errno 1101: "BLOB, TEXT, GEOMETRY or
JSON column can't have a default value".

Root cause: the Column struct had no way to distinguish expression defaults from
literal defaults. The needsQuotes() function treated all unrecognized values
(including function calls) as strings that needed quoting.

The fix adds a DefaultIsExpr field to Column, set during parsing by inspecting
the TiDB AST. Expression defaults are now formatted as DEFAULT (expr) while
literal defaults continue to be quoted as DEFAULT 'value'.

Also fixes parseExpression stripping trailing () from all zero-arg functions --
now only strips for timestamp-family functions (current_timestamp, now, etc.)
where MySQL's canonical form omits the parens.

Fixes #542

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Armand Parajon <armand@squareup.com>
…ing table

Simulates the real-world scenario where a JSON column with
DEFAULT (json_object()) is added to a table that already has
multiple columns including other JSON columns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Armand Parajon <armand@squareup.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Armand Parajon <armand@squareup.com>
@aparajon aparajon marked this pull request as ready for review April 20, 2026 21:19
@morgo morgo self-requested a review April 20, 2026 21:24
@aparajon aparajon merged commit c69dc30 into main Apr 20, 2026
15 of 20 checks passed
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.

2 participants