Skip to content

Fixed some defect on STR function#4104

Open
kelepcera wants to merge 8 commits intobabelfish-for-postgresql:BABEL_5_X_DEVfrom
kelepcera:fix/str_function
Open

Fixed some defect on STR function#4104
kelepcera wants to merge 8 commits intobabelfish-for-postgresql:BABEL_5_X_DEVfrom
kelepcera:fix/str_function

Conversation

@kelepcera
Copy link
Contributor

@kelepcera kelepcera commented Sep 18, 2025

Description

This MR aligns STR() with SQL Server in several major correctness areas (carry propagation, decimal-point placement, and negative rounding with decimal = 0). It also documents the remaining compatibility gaps for (a) 17-significant-digits normalization and (b) float tie boundary literals.

Fixed: major correctness issues

-- 1) Negative rounding, carry/sign handling
SELECT STR(-999.9, 6, 0) AS result10;           -- Expected (SQL Server): ' -1000'
GO
-- Before (Babelfish): -1090
-- After  (Babelfish): -1000

-- 2) Carry across the decimal; decimal-point placement
SELECT STR(1.9999, 6, 3) AS rounding_boundary;  -- Expected (SQL Server): '  2.000'
GO
-- Before (Babelfish): 10.000
-- After  (Babelfish):  2.000

-- 3) Additional boundary inputs (now consistent with SQL Server)
SELECT STR(2.9999, 6, 3) AS rounding_boundary;  -- Expected: '  3.000'
GO
-- Before (Babelfish):  10.000
-- After  (Babelfish):  3.000

SELECT STR(3.9999, 6, 3) AS rounding_boundary;  -- Expected: '  4.000'
GO
-- Before (Babelfish): 10.000 (mis-placed carry)
-- After  (Babelfish):  4.000

Why this matters: the old behavior produced numerically wrong strings (-1090 instead of -1000, 10.000 instead of 2.000/4.000) and broke SQL Server parity in common edge cases.

Still different (not fixed in this MR)

SQL Server I guess normalizes to at most 17 significant digits (round at digit 17 and zero-fill beyond) before any length/decimal formatting. We don’t yet enforce that step:

SELECT STR(12345678901234567890, 20) AS result_big1;
GO
-- SQL Server: 12345678901234567000
-- Babelfish : 12345678901234568000   <-- differs

SELECT STR(1234567890.1234567890, 22, 20) AS result_frac_prec;
GO
-- SQL Server: 1234567890.12345670000
-- Babelfish : 1234567890.12345680000 <-- differs

What changed (implementation)

  • I have added several comment to find_round_pos() function to increase readability so these changes will not affect the code.
  • In round_float_char() function I have also include 0. index to fix "STR(1.9999, 6, 3) " this type of inputs. In the old implementation the code will miss very first digit and it will always turn into a 10. By now it will catch and handle this kind of situations.
  • I also added "++float_char;" line to float_str() funtion to handle "STR(-999.9, 6, 0)" kind of inputs.

Corrected post-round carry propagation and decimal-point placement, including cases where carry expands the integer part (e.g., 1.9999 --> 2.000, 3.9999 --> 4.000) without misplacing the decimal or producing 10.000.

Fixed negative rounding with decimal = 0 so sign + carry produce the correct integer (e.g., -999.9 --> -1000) and align with SQL Server formatting.

Issues Resolved

[Issue Link]](#4103)

Test Scenarios Covered

  • Use case based -

  • Boundary conditions -

  • Arbitrary inputs -

  • Negative test cases -

  • Minor version upgrade tests -

  • Major version upgrade tests -

  • Performance tests -

  • Tooling impact -

  • Client tests -

Check List

  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is under the terms of the Apache 2.0 and PostgreSQL licenses, and grant any person obtaining a copy of the contribution permission to relicense all or a portion of my contribution to the PostgreSQL License solely to contribute all or a portion of my contribution to the PostgreSQL open source project.

For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@coveralls
Copy link
Collaborator

coveralls commented Sep 18, 2025

Pull Request Test Coverage Report for Build 20502144051

Details

  • 11 of 11 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.01%) to 76.871%

Totals Coverage Status
Change from base Build 20489420094: 0.01%
Covered Lines: 52489
Relevant Lines: 68282

💛 - Coveralls

Copy link
Contributor

@Yvinayak07 Yvinayak07 left a comment

Choose a reason for hiding this comment

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

Let's add test cases also.

@kelepcera
Copy link
Contributor Author

Let's add test cases also.

Hello, I have added several regression tests — you can check their results.
You will notice some differences in certain inputs, but most of them are normal. According to the official Microsoft documentation, float_expression is defined as:

"float_expression is an expression of approximate numeric (float) data type with a decimal point."

Because of this “approximate number” behavior, slight discrepancies (especially around .5 boundaries or values like 2.675) are expected and not considered bugs.

The only remaining problem is with numbers that exceed 17 significant digits: SQL Server truncates them, while our code sometimes rounds. I attempted a fix, but it caused regressions elsewhere, so I left it as is for now.

@kelepcera
Copy link
Contributor Author

kelepcera commented Oct 1, 2025

@Yvinayak07 Hello is there any update?
@tanyagupta17

@kelepcera
Copy link
Contributor Author

Hi, I just wanted to kindly check if you’ve had a chance to look at the merge request I opened for the fix. It’s a very small change and you can check in your local env adding some break points. Thank you.
@Yvinayak07 @tanyagupta17

Copy link
Contributor

Choose a reason for hiding this comment

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

Hi, could you please add some test cases including functions, procedures and views calling this function STR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, sure thank you!

Copy link
Contributor Author

@kelepcera kelepcera Nov 11, 2025

Choose a reason for hiding this comment

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

Hello again, it has already kind of test cases and I have just added more test cases to test new outputs and updated expected files.

/* =========================
0) Smoke: basic rounding (1 d.p., 2 d.p.)
========================= */
SELECT STR(123.355, 10, 1) AS s_1dp_up; -- MSSQL: ' 123.4'
Copy link
Contributor

Choose a reason for hiding this comment

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

Kindly you the term "-- TSQL:" instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you to inform me. I will fix them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was fixed.

@tanscorpio7 tanscorpio7 added the Pending Response Requested response from community reporter label Nov 1, 2025
@kelepcera
Copy link
Contributor Author

kelepcera commented Nov 14, 2025

Hello, is there any update? :) @tanyagupta17 @Yvinayak07 @rohit01010

@tanscorpio7 tanscorpio7 added In Review PR in review to be merged and removed Pending Response Requested response from community reporter labels Nov 18, 2025
@kelepcera
Copy link
Contributor Author

Hi there,
I hope you’re doing well. I wanted to kindly check in regarding the review for the Babelfish Extension MR I submitted about two weeks ago.
Whenever you have a moment to take a look, I’d really appreciate it. Thanks in advance.
@tanyagupta17 @Yvinayak07 @rohit01010

Copy link
Contributor

@tanyagupta17 tanyagupta17 left a comment

Choose a reason for hiding this comment

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

Hi @kelepcera could you please fix the failing test cases in this PR. Thanks!
I checked the test failures, could you please re-run your PR, these failures are fixed in recent times.

@kelepcera
Copy link
Contributor Author

Hi @kelepcera could you please fix the failing test cases in this PR. Thanks! I checked the test failures, could you please re-run your PR, these failures are fixed in recent times.

Hi @tanyagupta17 . I rebased my branch as a result of this the pipeline has been triggered. Every jobs has been finished successfully. And also thank you to take care of errors in my pipeline.

@kelepcera
Copy link
Contributor Author

kelepcera commented Jan 2, 2026

Hello @tanyagupta17 , is there any update about bugs?
@Yvinayak07 @rohit01010

@kelepcera
Copy link
Contributor Author

Hello everybody, is there any update? It should be ready to be merged.
@tanscorpio7 @tanyagupta17 @Yvinayak07 @rohit01010

Comment on lines +806 to +807
/* return VARCHAR with actual content length (no NUL) */
return return_varchar_pointer(buf, (int)strlen(buf));
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to how its done in earlier return statements, for example following case

/* not enough space for the carried_over digit, return *** */
				/*
				 * the space limitation goes by the one set before the
				 * rounding & carried over
				 */
				/*
				 * STR(9999.998, 7, 2) returns "*******" but STR(10000.000, 7,
				 * 2) returns "10000.0"
				 */
				/*
				 * which means the max length constraint of integer part is
				 * still 4 after rounding
				 */
				memset(buf, '*', size - 1);
				return return_varchar_pointer(buf, size - 1);

can we use size-1 instead of computing the length again using strlen, as (int)strlen(buf) will anyways be size-1 ?

++float_char; /* skip '-' in source */
}
memset(buf + num_spaces - 1, '1', 1);
memset(float_char, '0', 1);
Copy link
Contributor

@rohit01010 rohit01010 Jan 20, 2026

Choose a reason for hiding this comment

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

memset(float_char, '0', 1);

can we evaluate whether we need this or not ?

@rohit01010
Copy link
Contributor

rohit01010 commented Jan 20, 2026

Thanks @kelepcera for your patience! I've completed my review and left some comments. Please check the comments when you get a chance.

@tanscorpio7 tanscorpio7 added wip Work In Progress and removed In Review PR in review to be merged labels Feb 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wip Work In Progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants