Skip to content

parser: retain DECIMAL/NUMERIC scale (was truncated to 0)#52

Merged
chiradip merged 1 commit into
mainfrom
fix-decimal-numeric-scale
Jul 27, 2026
Merged

parser: retain DECIMAL/NUMERIC scale (was truncated to 0)#52
chiradip merged 1 commit into
mainfrom
fix-decimal-numeric-scale

Conversation

@chiradip

@chiradip chiradip commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

type_node->semantic_flags is uint16_t, but the scale of a DECIMAL(p,s) / NUMERIC(p,s) type was written as scale << 16 — shifted entirely out of the 16-bit field and truncated to 0. DECIMAL(10,2) recorded precision=10 but scale=0, silently discarding parsed information. (No UB — the shift is on a uint32_t temporary — just lost metadata.)

Found in the bottom-up parser audit alongside the nested-CREATE TRIGGER crash (separate PR). Minor severity: nothing downstream currently reads the packed precision/scale (the analyzer derives the type from the type name and strips the (...)), so this is a "parser must not silently drop what it parsed" correctness fix rather than an observable wrong-result today.

Change

Pack both values into semantic_flags: precision in the low byte, scale in the high byte. A byte each covers all real DECIMAL/NUMERIC types (ANSI max precision 38, and scale ≤ precision); both are clamped to 255 so an out-of-range literal cannot spill into the other field.

Decode is precision = flags & 0xFF, scale = (flags >> 8) & 0xFF.

Tests

tests/test_ddl_statements.cpp:

  • DECIMAL(10,2) → precision=10, scale=2;
  • NUMERIC(18) → precision=18, scale=0.

Falsifiable: the scale assertion fails under the old scale << 16. Full suite 37/37.

`type_node->semantic_flags` is uint16_t, but the scale of a
DECIMAL(p,s)/NUMERIC(p,s) type was written as `scale << 16` -- shifted
entirely out of the 16-bit field and truncated to 0. `DECIMAL(10,2)`
recorded precision=10 but scale=0, silently discarding parsed
information.

Pack both into semantic_flags instead: precision in the low byte, scale
in the high byte. A byte each covers all real DECIMAL/NUMERIC types (ANSI
max precision 38, scale <= precision); both are clamped to 255 so an
out-of-range literal cannot spill into the other field.

Tests (tests/test_ddl_statements.cpp): DECIMAL(10,2) retains
precision=10/scale=2; NUMERIC(18) retains precision=18/scale=0.
Falsifiable: the scale assertion fails under the old `scale << 16`.
Full suite 37/37.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FyKDAbMWGwiZq4iJx3imsg
@chiradip
chiradip merged commit 2b88d18 into main Jul 27, 2026
8 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.

1 participant