Skip to content

feat(query): support TH/th ordinal and V shift patterns in to_char#19830

Draft
kimjune01 wants to merge 6 commits into
databendlabs:mainfrom
kimjune01:feat/to-char-th-ordinal
Draft

feat(query): support TH/th ordinal and V shift patterns in to_char#19830
kimjune01 wants to merge 6 commits into
databendlabs:mainfrom
kimjune01:feat/to-char-th-ordinal

Conversation

@kimjune01

@kimjune01 kimjune01 commented May 9, 2026

Copy link
Copy Markdown

I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/

Summary

  • Implement TH/th ordinal number suffix pattern for the postgres-compatible to_char number formatting function. Appends ST, ND, RD, or TH (upper or lower) following PostgreSQL teen-number rules.
  • Implement V shift-digits pattern that multiplies the input by 10^n where n is the count of digit positions after V.
  • Fix Tk0 not checking NumFlag::Multi in prepare(), which would corrupt the multiplier for formats like 09V00.
  • Use round_ties_even() for float V to match PostgreSQL's IEEE 754 tie-breaking.
  • Use checked arithmetic for integer V to prevent overflow on large multi values.

Closes part of #16524

Tests

  • Unit Test
  • Logic Test
  • Benchmark Test
  • No Test - Explain why

Type of change

  • Bug Fix (non-breaking change which fixes an issue)
  • New Feature (non-breaking change which adds functionality)
  • Breaking Change (fix or feature that could cause existing functionality not to work as expected)
  • Documentation Update
  • Refactoring
  • Performance Improvement
  • Other (please describe):

Test plan

  • Unit tests for TH/th: values 0-4, teens 11-13, twenties 21-23, hundreds 111-113
  • Upper and lowercase ordinal variants
  • FM (fill mode) with ordinal
  • Negative values with ordinal
  • Ordinal with trailing literals and signs
  • V with integers: 99V999, 9V9
  • V with floats: ties-to-even rounding verification
  • V negative values
  • Clippy clean, cargo fmt clean

This change is Reviewable

kimjune01 added 4 commits May 9, 2026 10:29
Implements the TH and th format patterns for the postgres-compatible
number to_char function. TH appends uppercase ordinal suffixes
(ST, ND, RD, TH) and th appends lowercase equivalents, following
PostgreSQL semantics including teen-number rules (11th, 12th, 13th).

Closes part of databendlabs#16524
Implements the V format pattern for the postgres-compatible number
to_char function. V multiplies the input by 10^n where n is the
count of digit positions after V, then formats as an integer.
Works for both integer and float inputs.

Closes part of databendlabs#16524
- Move TH/th suffix emission from post-processing to inline at token
  position, so trailing literals and signs appear after the suffix
- Fix Tk0 not checking NumFlag::Multi in prepare(), which corrupted
  multi count for formats like "09V00"
- Use round_ties_even() instead of round() for float V to match
  PostgreSQL's IEEE 754 tie-breaking semantics
- Use checked arithmetic for integer V to prevent overflow/panic
  on large multi values

Reviewed by codex (GPT-5.5) and Gemini 3.1 Pro.
@github-actions github-actions Bot added the pr-feature this PR introduces a new feature to the codebase label May 9, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 21fdfaa4cf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// then rounds to the nearest integer.
// Total output width = pre + multi digits.
let multiplier = 10f64.powi(self.multi as i32);
let shifted = (value.abs() * multiplier).round_ties_even();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use away-from-zero rounding for V shift ties

The V implementation for floating-point values currently uses round_ties_even(), but PostgreSQL rounds to_char(..., '...V...') half values away from zero (for example, to_char(12.45, '99V9') is documented as 125). With the current code, tie cases like 12.45 produce 124, so Databend will return PostgreSQL-incompatible results for common .5 boundaries.

Useful? React with 👍 / 👎.

NumPoz::TkPR => (),
NumPoz::TkFM => (),
NumPoz::TkV => (),
NumPoz::TkTH | NumPoz::Tkth => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip ordinal suffix conversion for negative TH/th

The ordinal suffix branch always appends st/nd/rd/th, but PostgreSQL's numeric formatting rules state that TH/th does not convert values less than zero (and also not fractional inputs). As written, calls like to_char(-1, '9th') will emit an ordinal suffix, which breaks PostgreSQL compatibility for negative values.

Useful? React with 👍 / 👎.

@kimjune01

Copy link
Copy Markdown
Author

I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/

@kimjune01 kimjune01 marked this pull request as draft May 20, 2026 22:05
@kimjune01

Copy link
Copy Markdown
Author

Cannot validate on current setup, so drafting. Please close or take it over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-feature this PR introduces a new feature to the codebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant