Thread
Commits
-
Support RN (roman-numeral format) in to_number().
- 172e6b3adb2e 18.0 landed
-
[PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-08-30T07:21:52Z
Hi, While looking at formatting.c file, I noticed a TODO about "add support for roman number to standard number conversion" ( https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/formatting.c#L52 ) I have attached the patch that adds support for this and converts roman numerals to standard numbers (1 to 3999) while also checking if roman numerals are valid or not. I have also added a new error code: ERRCODE_INVALID_ROMAN_NUMERAL in case of invalid numerals. A few examples: postgres=# SELECT to_number('MC', 'RN'); to_number ----------- 1100 (1 row) postgres=# SELECT to_number('XIV', 'RN'); to_number ----------- 14 (1 row) postgres=# SELECT to_number('MMMCMXCIX', 'RN'); to_number ----------- 3999 (1 row) postgres=# SELECT to_number('MCCD', 'RN'); ERROR: invalid roman numeral I would appreciate your feedback on the following cases: - Is it okay for the function to handle Roman numerals in a case-insensitive way? (e.g., 'XIV', 'xiv', and 'Xiv' are all seen as 14). - How should we handle Roman numerals with leading or trailing spaces, like ' XIV' or 'MC '? Should we trim the spaces, or would it be better to throw an error in such cases? I have tested the changes and would appreciate any suggestions for improvement. I will update the docs and regressions in the next version of patch. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Maciek Sakrejda <m.sakrejda@gmail.com> — 2024-09-02T18:40:43Z
Thanks for the contribution. I took a look at the patch, and it works as advertised. It's too late for the September commitfest, but I took the liberty of registering your patch for the November CF [1]. In the course of that, I found an older thread proposing this feature seven years ago [2]. That patch was returned with feedback and (as far as I can tell), was not followed-up on by the author. You may want to review that thread for feedback; I won't repeat it here. On Fri, Aug 30, 2024 at 12:22 AM Hunaid Sohail <hunaidpgml@gmail.com> wrote: >While looking at formatting.c file, I noticed a TODO about "add support for roman number to standard number conversion" (https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/formatting.c#L52) Your patch should also remove the TODO =) > - Is it okay for the function to handle Roman numerals in a case-insensitive way? (e.g., 'XIV', 'xiv', and 'Xiv' are all seen as 14). The patch in the thread I linked also took a case-insensitive approach. I did not see any objections to that, and it seems reasonable to me as well. > - How should we handle Roman numerals with leading or trailing spaces, like ' XIV' or 'MC '? Should we trim the spaces, or would it be better to throw an error in such cases? I thought we could reference existing to_number behavior here, but after playing with it a bit, I'm not really sure what that is: -- single leading space maciek=# select to_number(' 1', '9'); to_number ----------- 1 (1 row) -- two leading spaces maciek=# select to_number(' 1', '9'); ERROR: invalid input syntax for type numeric: " " -- two leading spaces and template pattern with a decimal maciek=# select to_number(' 1', '9D9'); to_number ----------- 1 (1 row) Separately, I also noticed some unusual Roman representations work with your patch: postgres=# select to_number('viv', 'RN'); to_number ----------- 9 (1 row) Is this expected? In contrast, some somewhat common alternative representations don't work: postgres=# select to_number('iiii', 'RN'); ERROR: invalid roman numeral I know this is expected, but is this the behavior we want? If so, we probably want to reject the former case, too. If not, maybe that one is okay, too. I know I've probably offered more questions than answers, but I hope finding the old thread here is useful. Thanks, Maciek [1]: https://commitfest.postgresql.org/50/5233/ [2]: https://www.postgresql.org/message-id/flat/CAGMVOduAJ9wKqJXBYnmFmEetKxapJxrG3afUwpbOZ6n_dWaUnA%40mail.gmail.com -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-03T13:28:59Z
On Mon, Sep 2, 2024 at 11:41 PM Maciek Sakrejda <m.sakrejda@gmail.com> wrote: > Thanks for the contribution. > > I took a look at the patch, and it works as advertised. It's too late > for the September commitfest, but I took the liberty of registering > your patch for the November CF [1]. In the course of that, I found an > older thread proposing this feature seven years ago [2]. That patch > was returned with feedback and (as far as I can tell), was not > followed-up on by the author. You may want to review that thread for > feedback; I won't repeat it here. > I submitted the patch on Aug 30 because I read that new patches should be submitted in CF with "Open" status. > On Fri, Aug 30, 2024 at 12:22 AM Hunaid Sohail <hunaidpgml@gmail.com> > wrote: > >While looking at formatting.c file, I noticed a TODO about "add support > for roman number to standard number conversion" ( > https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/formatting.c#L52 > ) > > Your patch should also remove the TODO =) > Noted. > - How should we handle Roman numerals with leading or trailing spaces, > like ' XIV' or 'MC '? Should we trim the spaces, or would it be better to > throw an error in such cases? > > I thought we could reference existing to_number behavior here, but > after playing with it a bit, I'm not really sure what that is: > > -- single leading space > maciek=# select to_number(' 1', '9'); > to_number > ----------- > 1 > (1 row) > > -- two leading spaces > maciek=# select to_number(' 1', '9'); > ERROR: invalid input syntax for type numeric: " " > -- two leading spaces and template pattern with a decimal > maciek=# select to_number(' 1', '9D9'); > to_number > ----------- > 1 > (1 row) > Yes, you are right. I can't understand the behaviour of trailing spaces too. Trailing spaces are ignored (doesn't matter how many spaces) but leading spaces are ignored if there is 1 leading space. For more leading spaces, error is returned. A few cases of trailing spaces. postgres=# select to_number(' 1', '9'); ERROR: invalid input syntax for type numeric: " " postgres=# select to_number('1 ', '9'); to_number ----------- 1 (1 row) postgres=# select to_number('1 ', '9'); to_number ----------- 1 (1 row) postgres=# select to_number('1 ', '9'); to_number ----------- 1 (1 row) Separately, I also noticed some unusual Roman representations work > with your patch: > > postgres=# select to_number('viv', 'RN'); > to_number > ----------- > 9 > (1 row) > > Is this expected? In contrast, some somewhat common alternative > representations don't work: > > postgres=# select to_number('iiii', 'RN'); > ERROR: invalid roman numeral > > I know this is expected, but is this the behavior we want? If so, we > probably want to reject the former case, too. If not, maybe that one > is okay, too. > Yes, 'viv' is invalid. Thanks for pointing this out. Also, found a few other invalid cases like 'lxl' or 'dcd'. I will fix them in the next patch. Thank you for your feedback. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Maciek Sakrejda <maciek@pganalyze.com> — 2024-09-03T15:47:43Z
On Tue, Sep 3, 2024 at 6:29 AM Hunaid Sohail <hunaidpgml@gmail.com> wrote: > I submitted the patch on Aug 30 because I read that new patches should be submitted in CF with "Open" status. Oh my bad! I missed that you had submitted it to the September CF: https://commitfest.postgresql.org/49/5221/ I don't see a way to just delete CF entries, so I've marked the November one that I created as Withdrawn. I'll add myself as reviewer to the September CF entry. Thanks, Maciek
-
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-05T08:07:03Z
Hi, I have attached a new patch v2 with following changes: - Handled invalid cases like 'viv', 'lxl', and 'dcd'. - Changed errcode to 22P07 because 22P06 was already taken. - Removed TODO. - Added a few positive & negative tests. - Updated documentation. Looking forward to your feedback. Regards, Hunaid Sohail On Tue, Sep 3, 2024 at 8:47 PM Maciek Sakrejda <maciek@pganalyze.com> wrote: > On Tue, Sep 3, 2024 at 6:29 AM Hunaid Sohail <hunaidpgml@gmail.com> wrote: > > I submitted the patch on Aug 30 because I read that new patches should > be submitted in CF with "Open" status. > > Oh my bad! I missed that you had submitted it to the September CF: > https://commitfest.postgresql.org/49/5221/ > > I don't see a way to just delete CF entries, so I've marked the > November one that I created as Withdrawn. > > I'll add myself as reviewer to the September CF entry. > > Thanks, > Maciek >
-
Re: [PATCH] Add roman support for to_number function
Aleksander Alekseev <aleksander@timescale.com> — 2024-09-05T09:41:42Z
Hi, > I have attached a new patch v2 with following changes: > > - Handled invalid cases like 'viv', 'lxl', and 'dcd'. > - Changed errcode to 22P07 because 22P06 was already taken. > - Removed TODO. > - Added a few positive & negative tests. > - Updated documentation. > > Looking forward to your feedback. While playing with the patch I noticed that to_char(..., 'RN') doesn't seem to be test-covered. I suggest adding the following test: ``` WITH rows AS ( SELECT i, to_char(i, 'FMRN') AS roman FROM generate_series(1, 3999) AS i ) SELECT bool_and(to_number(roman, 'RN') = i) FROM rows; bool_and ---------- t ``` ... in order to fix this while on it. The query takes ~12 ms on my laptop. -- Best regards, Aleksander Alekseev -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-05T13:07:34Z
On Thu, Sep 5, 2024 at 2:41 PM Aleksander Alekseev <aleksander@timescale.com> wrote: > > While playing with the patch I noticed that to_char(..., 'RN') doesn't > seem to be test-covered. I suggest adding the following test: > > ``` > WITH rows AS ( > SELECT i, to_char(i, 'FMRN') AS roman > FROM generate_series(1, 3999) AS i > ) SELECT bool_and(to_number(roman, 'RN') = i) FROM rows; > > bool_and > ---------- > t > ``` > I also noticed there are no tests for to_char roman format. The test you provided covers roman format in both to_char and to_number. I will add it. Thank you. Regards, Hunaid Sohail
-
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-07T09:24:23Z
Hi, On Thu, Sep 5, 2024 at 2:41 PM Aleksander Alekseev <aleksander@timescale.com> > wrote: > >> >> While playing with the patch I noticed that to_char(..., 'RN') doesn't >> seem to be test-covered. I suggest adding the following test: >> >> ``` >> WITH rows AS ( >> SELECT i, to_char(i, 'FMRN') AS roman >> FROM generate_series(1, 3999) AS i >> ) SELECT bool_and(to_number(roman, 'RN') = i) FROM rows; >> >> bool_and >> ---------- >> t >> ``` >> > > I have added this test in the attached patch (v3). Thank you once again, Aleksander, for the suggestion. Regards, Hunaid Sohail
-
Re: [PATCH] Add roman support for to_number function
Maciek Sakrejda <m.sakrejda@gmail.com> — 2024-09-07T18:51:29Z
The following review has been posted through the commitfest application: make installcheck-world: tested, passed Implements feature: tested, failed Spec compliant: tested, failed Documentation: tested, passed Tested again, and the patch looks good. It does not accept leading or trailing whitespace, which seems reasonable, given the unclear behavior of to_number with other format strings. It also rejects less common Roman spellings like "IIII". I don't feel strongly about that one way or the other, but perhaps a test codifying that behavior would be useful to make it clear it's intentional. I'm marking it RfC. The new status of this patch is: Ready for Committer
-
Re: [PATCH] Add roman support for to_number function
Maciek Sakrejda <m.sakrejda@gmail.com> — 2024-09-07T18:57:00Z
Sorry, it looks like I failed to accurately log my review in the review app due to the current broken layout issues [1]. The summary should be: make installcheck-world: tested, passed Implements feature: tested, passed Spec compliant: not tested (not sure what the spec has to say about this) Documentation: tested, passed [1]: https://www.postgresql.org/message-id/flat/CAD68Dp1GgTeBiA0YVWXpfPCMC7%3DnqBCLn6%2BhuOkWURcKRnFw5g%40mail.gmail.com
-
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2024-09-07T23:09:40Z
Maciek Sakrejda <m.sakrejda@gmail.com> writes: > Tested again, and the patch looks good. It does not accept leading or trailing whitespace, which seems reasonable, given the unclear behavior of to_number with other format strings. It also rejects less common Roman spellings like "IIII". I don't feel strongly about that one way or the other, but perhaps a test codifying that behavior would be useful to make it clear it's intentional. Yeah, I don't have a strong feeling about that either, but probably being strict is better. to_number has a big problem with "garbage in garbage out" already, and being lax will make that worse. A few notes from a quick read of the patch: * roman_to_int() should have a header comment, notably explaining its result convention. I find it fairly surprising that "0" means an error --- I realize that Roman notation can't represent zero, but wouldn't it be better to use -1? * Do *not* rely on toupper(). There are multiple reasons why not, but in this context the worst one is that in Turkish locales it's likely to translate "i" to "İ", on which you will fail. I'd use pg_ascii_toupper(). * I think roman_to_int() is under-commented internally too. To start with, where did the magic "15" come from? And why should we have such a test anyway --- what if the format allows for trailing stuff after the roman numeral? (That is, I think you need to fix this so that roman_to_int reports how much data it ate, instead of assuming that it must read to the end of the input.) The logic for detecting invalid numeral combinations feels a little opaque too. Do you have a source for the rules you're implementing, and if so could you cite it? * This code will get run through pgindent before commit, so you might want to revisit whether your comments will still look nice afterwards. There's not a lot of consistency in them about initial cap versus lower case or trailing period versus not, too. * roman_result could be declared where used, no? * I'm not really convinced that we need a new errcode ERRCODE_INVALID_ROMAN_NUMERAL rather than using a generic one like ERRCODE_INVALID_TEXT_REPRESENTATION. However, if we do do it like that, why did you pick the out-of-sequence value 22P07? * Might be good to have a few test cases demonstrating what happens when there's other stuff combined with the RN format spec. Notably, even if RN itself won't eat whitespace, there had better be a way to write the format string to allow that. * Further to Aleksander's point about lack of test coverage for the to_char direction, I see from https://coverage.postgresql.org/src/backend/utils/adt/formatting.c.gcov.html that almost none of the existing roman-number code paths are covered today. While it's not strictly within the charter of this patch to improve that, maybe we should try to do so --- at the very least it'd raise formatting.c's coverage score a few notches. regards, tom lane
-
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2024-09-08T21:44:20Z
I wrote: > * Further to Aleksander's point about lack of test coverage for > the to_char direction, I see from > https://coverage.postgresql.org/src/backend/utils/adt/formatting.c.gcov.html > that almost none of the existing roman-number code paths are covered > today. While it's not strictly within the charter of this patch > to improve that, maybe we should try to do so --- at the very > least it'd raise formatting.c's coverage score a few notches. For the archives' sake: I created a patch and a separate discussion thread [1] for that. regards, tom lane [1] https://www.postgresql.org/message-id/flat/2956175.1725831136@sss.pgh.pa.us
-
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-09T12:45:17Z
Hi, On Sun, Sep 8, 2024 at 4:09 AM Tom Lane <tgl@sss.pgh.pa.us> wrote: > A few notes from a quick read of the patch: > > * roman_to_int() should have a header comment, notably explaining its > result convention. I find it fairly surprising that "0" means an > error --- I realize that Roman notation can't represent zero, but > wouldn't it be better to use -1? > Noted. > > * Do *not* rely on toupper(). There are multiple reasons why not, > but in this context the worst one is that in Turkish locales it's > likely to translate "i" to "İ", on which you will fail. I'd use > pg_ascii_toupper(). > Noted. > > * I think roman_to_int() is under-commented internally too. > To start with, where did the magic "15" come from? And why > should we have such a test anyway --- what if the format allows > for trailing stuff after the roman numeral? (That is, I think > you need to fix this so that roman_to_int reports how much data > it ate, instead of assuming that it must read to the end of the > input.) MMMDCCCLXXXVIII is the longest valid standard roman numeral (15 characters). I will add appropriate comment on length check. I am not sure I am able to understand the latter part. Could you please elaborate it? Are you referring to cases like these? SELECT to_number('CXXIII foo', 'RN foo'); SELECT to_number('CXXIII foo', 'RN'); Please check my comments on Oracle's behaviour below. > The logic for detecting invalid numeral combinations > feels a little opaque too. Do you have a source for the rules > you're implementing, and if so could you cite it? > There are many sources on the internet. A few sources: 1. https://www.toppr.com/guides/maths/knowing-our-numbers/roman-numerals/ 2. https://www.cuemath.com/numbers/roman-numerals/ Note that we are following the standard form: https://en.wikipedia.org/wiki/Roman_numerals#Standard_form > > * This code will get run through pgindent before commit, so you > might want to revisit whether your comments will still look nice > afterwards. There's not a lot of consistency in them about initial > cap versus lower case or trailing period versus not, too. > Noted. > > * roman_result could be declared where used, no? > Noted. > > * I'm not really convinced that we need a new errcode > ERRCODE_INVALID_ROMAN_NUMERAL rather than using a generic one like > ERRCODE_INVALID_TEXT_REPRESENTATION. However, if we do do it > like that, why did you pick the out-of-sequence value 22P07? > 22P07 is not out-of-sequence. 22P01 to 22P06 are already used. However, I do agree with you that we can use ERRCODE_INVALID_TEXT_REPRESENTATION. I will change it. > > * Might be good to have a few test cases demonstrating what happens > when there's other stuff combined with the RN format spec. Notably, > even if RN itself won't eat whitespace, there had better be a way > to write the format string to allow that. > The current patch (v3) simply ignores other formats with RN except when RN is used EEEE which returns error. ``` postgres=# SELECT to_number('CXXIII', 'foo RN'); to_number ----------- 123 (1 row) postgres=# SELECT to_number('CXXIII', 'MIrn'); to_number ----------- 123 (1 row) postgres=# SELECT to_number('CXXIII', 'EEEErn'); ERROR: "EEEE" must be the last pattern used ``` However, I think that other formats except FM should be rejected when used with RN in NUMDesc_prepare function. Any opinions? If we look into Oracle, they are strict in this regard and don't allow any other format with RN. 1. SELECT to_char(12, 'MIrn') from dual; 2. SELECT to_char(12, 'foo RN') from dual; results in error: ORA-01481: invalid number format model I also found that there is no check when RN is used twice (both in to_char and to_number) and that results in unexpected output. ``` postgres=# SELECT to_number('CXXIII', 'RNrn'); to_number ----------- 123 (1 row) postgres=# SELECT to_char(12, 'RNrn'); to_char -------------------------------- XII xii (1 row) postgres=# SELECT to_char(12, 'rnrn'); to_char -------------------------------- xii xii (1 row) postgres=# SELECT to_char(12, 'FMrnrn'); to_char --------- xiixii (1 row) ``` > * Further to Aleksander's point about lack of test coverage for > the to_char direction, I see from > > https://coverage.postgresql.org/src/backend/utils/adt/formatting.c.gcov.html > that almost none of the existing roman-number code paths are covered > today. While it's not strictly within the charter of this patch > to improve that, maybe we should try to do so --- at the very > least it'd raise formatting.c's coverage score a few notches. > > I see that you have provided a patch to increase test coverage of to_char roman format including some other formats. I will try to add more tests for the to_number roman format. I will provide the next patch soon. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-12T07:44:23Z
Hi, I have started working on the next version of the patch and have addressed the smaller issues identified by Tom. Before proceeding further, I would like to have opinions on some comments/questions in my previous email. Regards, Hunaid Sohail On Mon, Sep 9, 2024 at 5:45 PM Hunaid Sohail <hunaidpgml@gmail.com> wrote: > Hi, > > On Sun, Sep 8, 2024 at 4:09 AM Tom Lane <tgl@sss.pgh.pa.us> wrote: > >> A few notes from a quick read of the patch: >> >> * roman_to_int() should have a header comment, notably explaining its >> result convention. I find it fairly surprising that "0" means an >> error --- I realize that Roman notation can't represent zero, but >> wouldn't it be better to use -1? >> > > Noted. > > >> >> * Do *not* rely on toupper(). There are multiple reasons why not, >> but in this context the worst one is that in Turkish locales it's >> likely to translate "i" to "İ", on which you will fail. I'd use >> pg_ascii_toupper(). >> > > Noted. > > >> >> * I think roman_to_int() is under-commented internally too. >> To start with, where did the magic "15" come from? And why >> should we have such a test anyway --- what if the format allows >> for trailing stuff after the roman numeral? (That is, I think >> you need to fix this so that roman_to_int reports how much data >> it ate, instead of assuming that it must read to the end of the >> input.) > > > MMMDCCCLXXXVIII is the longest valid standard roman numeral (15 > characters). I will add appropriate comment on length check. > > I am not sure I am able to understand the latter part. Could you please > elaborate it? > Are you referring to cases like these? > SELECT to_number('CXXIII foo', 'RN foo'); > SELECT to_number('CXXIII foo', 'RN'); > Please check my comments on Oracle's behaviour below. > > > >> The logic for detecting invalid numeral combinations >> feels a little opaque too. Do you have a source for the rules >> you're implementing, and if so could you cite it? >> > > There are many sources on the internet. > A few sources: > 1. https://www.toppr.com/guides/maths/knowing-our-numbers/roman-numerals/ > 2. https://www.cuemath.com/numbers/roman-numerals/ > > Note that we are following the standard form: > https://en.wikipedia.org/wiki/Roman_numerals#Standard_form > > >> >> * This code will get run through pgindent before commit, so you >> might want to revisit whether your comments will still look nice >> afterwards. There's not a lot of consistency in them about initial >> cap versus lower case or trailing period versus not, too. >> > > Noted. > > >> >> * roman_result could be declared where used, no? >> > > Noted. > > >> >> * I'm not really convinced that we need a new errcode >> ERRCODE_INVALID_ROMAN_NUMERAL rather than using a generic one like >> ERRCODE_INVALID_TEXT_REPRESENTATION. However, if we do do it >> like that, why did you pick the out-of-sequence value 22P07? >> > > 22P07 is not out-of-sequence. 22P01 to 22P06 are already used. > However, I do agree with you that we can use > ERRCODE_INVALID_TEXT_REPRESENTATION. I will change it. > > >> >> * Might be good to have a few test cases demonstrating what happens >> when there's other stuff combined with the RN format spec. Notably, >> even if RN itself won't eat whitespace, there had better be a way >> to write the format string to allow that. >> > > The current patch (v3) simply ignores other formats with RN except when RN > is used EEEE which returns error. > ``` > postgres=# SELECT to_number('CXXIII', 'foo RN'); > to_number > ----------- > 123 > (1 row) > > postgres=# SELECT to_number('CXXIII', 'MIrn'); > to_number > ----------- > 123 > (1 row) > > postgres=# SELECT to_number('CXXIII', 'EEEErn'); > ERROR: "EEEE" must be the last pattern used > ``` > > However, I think that other formats except FM should be rejected when used > with RN in NUMDesc_prepare function. Any opinions? > > If we look into Oracle, they are strict in this regard and don't allow any > other format with RN. > 1. SELECT to_char(12, 'MIrn') from dual; > 2. SELECT to_char(12, 'foo RN') from dual; > results in error: > ORA-01481: invalid number format model > > I also found that there is no check when RN is used twice (both in to_char > and to_number) and that results in unexpected output. > > ``` > postgres=# SELECT to_number('CXXIII', 'RNrn'); > to_number > ----------- > 123 > (1 row) > > postgres=# SELECT to_char(12, 'RNrn'); > to_char > -------------------------------- > XII xii > (1 row) > > postgres=# SELECT to_char(12, 'rnrn'); > to_char > -------------------------------- > xii xii > (1 row) > > postgres=# SELECT to_char(12, 'FMrnrn'); > to_char > --------- > xiixii > (1 row) > ``` > > >> * Further to Aleksander's point about lack of test coverage for >> the to_char direction, I see from >> >> https://coverage.postgresql.org/src/backend/utils/adt/formatting.c.gcov.html >> that almost none of the existing roman-number code paths are covered >> today. While it's not strictly within the charter of this patch >> to improve that, maybe we should try to do so --- at the very >> least it'd raise formatting.c's coverage score a few notches. >> >> > I see that you have provided a patch to increase test coverage of to_char > roman format including some other formats. I will try to add more tests for > the to_number roman format. > > > I will provide the next patch soon. > > Regards, > Hunaid Sohail > -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-09-19T07:51:51Z
Hi, I have attached a new patch with following changes: - Addressed minor issues identified by Tom. - Rejected other formats with RN and updated the docs. - Added a few more tests. Regards, Hunaid Sohail >
-
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-10-30T07:07:51Z
Hi, I have attached a rebased patch if someone wants to review in the next CF. No changes as compared to v4. Regards, Hunaid Sohail >
-
Re: [PATCH] Add roman support for to_number function
Tomas Vondra <tomas@vondra.me> — 2024-12-08T00:36:38Z
Hi, On 10/30/24 08:07, Hunaid Sohail wrote: > Hi, > > I have attached a rebased patch if someone wants to review in the next > CF. No changes as compared to v4. > > Regards, > Hunaid Sohail > Thanks for a nice patch. I did a quick review today, seems almost there, I only have a couple minor comments: 1) Template Patterns for Numeric Formatting Why the wording change? "input between 1 and 3999" sounds fine to me. 2) The docs say "standard numbers" but I'm not sure what that is? We don't use that term anywhere else, I think. Same for "standard roman numeral". 3) A couple comments need a bit of formatting. Multi-line comments should start with an empty line, some lines are a bit too long. 4) I was wondering if the regression tests check all interesting cases, and it seems none of the tests hit these two cases: if (vCount > 1 || lCount > 1 || dCount > 1) return -1; and if (!IS_VALID_SUB_COMB(currChar, nextChar)) return -1; I haven't tried constructing tests to hit those cases, though. Seems ready to go otherwise. regards -- Tomas Vondra -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-12-09T06:09:37Z
Hi, Thanks for reviewing this patch. On Mon, Dec 9, 2024 at 3:07 AM Tomas Vondra <tomas@vondra.me> wrote: > Thanks for a nice patch. I did a quick review today, seems almost there, > I only have a couple minor comments: > > 1) Template Patterns for Numeric Formatting > > Why the wording change? "input between 1 and 3999" sounds fine to me. > input... seemed to refer to numeric input for to_char roman format. But, after roman support in to_number function shouldn't we modify it? It is the reason I changed it to "valid for numbers 1 to 3999". 2) The docs say "standard numbers" but I'm not sure what that is? We > don't use that term anywhere else, I think. Same for "standard roman > numeral". > I will change "standard numbers" to "numbers". Note that we are following the standard form. There are other forms too. For example, 4 can be represented as IV (standard) or IIII (non standard). https://en.wikipedia.org/wiki/Roman_numerals#Standard_form > 3) A couple comments need a bit of formatting. Multi-line comments > should start with an empty line, some lines are a bit too long. > I will fix the multi-line formatting. > 4) I was wondering if the regression tests check all interesting cases, > and it seems none of the tests hit these two cases: > > if (vCount > 1 || lCount > 1 || dCount > 1) > return -1; > SELECT to_number('viv', 'RN') test covers this if statement for the subtraction part. But, I noticed that no test covers simple counts of V, L, D. I will add SELECT to_number('VV', 'RN') for that. > and > > if (!IS_VALID_SUB_COMB(currChar, nextChar)) > return -1; > Noted. SELECT to_number('IL', 'RN') test can be added. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2024-12-13T05:29:28Z
Hi, > On Mon, Dec 9, 2024 at 3:07 AM Tomas Vondra <tomas@vondra.me> wrote: > >> Thanks for a nice patch. I did a quick review today, seems almost there, >> I only have a couple minor comments: >> >> 1) Template Patterns for Numeric Formatting >> >> Why the wording change? "input between 1 and 3999" sounds fine to me. >> > input... seemed to refer to numeric input for to_char roman format. But, > after roman support in to_number function shouldn't we modify it? It is the > reason I changed it to "valid for numbers 1 to 3999". > > 2) The docs say "standard numbers" but I'm not sure what that is? We >> don't use that term anywhere else, I think. Same for "standard roman >> numeral". >> > I will change "standard numbers" to "numbers". > Note that we are following the standard form. There are other forms too. > For example, 4 can be represented as IV (standard) or IIII (non standard). > https://en.wikipedia.org/wiki/Roman_numerals#Standard_form > > >> 3) A couple comments need a bit of formatting. Multi-line comments >> should start with an empty line, some lines are a bit too long. >> > I will fix the multi-line formatting. > > >> 4) I was wondering if the regression tests check all interesting cases, >> and it seems none of the tests hit these two cases: >> >> if (vCount > 1 || lCount > 1 || dCount > 1) >> return -1; >> > SELECT to_number('viv', 'RN') test covers this if statement for the > subtraction part. But, I noticed that no test covers simple counts of V, L, > D. > I will add SELECT to_number('VV', 'RN') for that. > > >> and >> >> if (!IS_VALID_SUB_COMB(currChar, nextChar)) >> return -1; >> > Noted. SELECT to_number('IL', 'RN') test can be added. > I’ve attached a new patch that addresses comments 2, 3, and 4 from Tomas. Looking forward to your feedback. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2025-01-18T00:27:43Z
Hunaid Sohail <hunaidpgml@gmail.com> writes: > I’ve attached a new patch that addresses comments 2, 3, and 4 from Tomas. I'm still quite unhappy that this doesn't tolerate trailing whitespace. That's not how other format patterns work, and it makes it impossible to round-trip the output of to_char(..., 'RN'). I think the core of the problem is that you tried to cram the logic in where the existing "not implemented" error is thrown. But on inspection there is nothing sane about that entire "Roman correction" stanza -- what it does is either useless (zeroing already-zeroed fields) or in the wrong place (if we don't want to allow other flags with IS_ROMAN, that should be done via an error in NUMDesc_prepare, like other similar cases). In the attached I moved the roman_to_int call into NUM_processor's main loop so it's more like other format patterns, and fixed it to not eat any more characters than it should. This might allow putting back some format-combination capabilities, but other than the whitespace angle I figure we can leave that for people to request it. regards, tom lane
-
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2025-01-20T07:32:51Z
Hi Tom, On Sat, Jan 18, 2025 at 5:27 AM Tom Lane <tgl@sss.pgh.pa.us> wrote: > Hunaid Sohail <hunaidpgml@gmail.com> writes: > > I’ve attached a new patch that addresses comments 2, 3, and 4 from Tomas. > > I'm still quite unhappy that this doesn't tolerate trailing > whitespace. That's not how other format patterns work, and it makes > it impossible to round-trip the output of to_char(..., 'RN'). > I think the core of the problem is that you tried to cram the logic > in where the existing "not implemented" error is thrown. But on > inspection there is nothing sane about that entire "Roman correction" > stanza -- what it does is either useless (zeroing already-zeroed > fields) or in the wrong place (if we don't want to allow other flags > with IS_ROMAN, that should be done via an error in NUMDesc_prepare, > like other similar cases). In the attached I moved the roman_to_int > call into NUM_processor's main loop so it's more like other format > patterns, and fixed it to not eat any more characters than it should. > This might allow putting back some format-combination capabilities, > but other than the whitespace angle I figure we can leave that for > people to request it. > Thank you for the tweaks to the patch. Overall, it looks great. Initially, when I looked at the test case: SELECT to_number('M CC', 'RN'); I was confused about whether it should be 'MCC'. After further inspection, I realized that the output is 1000 for 'M'. The format of the input can be a bit unclear. Perhaps we could add a note in the documentation or issue a warning in roman_to_int function when input is truncated, to clarify this behavior. + bool truncated = false; + + /* + * Collect and decode valid roman numerals, consuming at most + * MAX_ROMAN_LEN characters. We do this in a separate loop to avoid + * repeated decoding and because the main loop needs to know when it's at + * the last numeral. + */ + for (len = 0; len < MAX_ROMAN_LEN && !OVERLOAD_TEST; len++) + { + char currChar = pg_ascii_toupper(*Np->inout_p); + int currValue = ROMAN_VAL(currChar); + + if (currValue == 0) + { + truncated = true; + break; /* Not a valid roman numeral. */ + } + romanChars[len] = currChar; + romanValues[len] = currValue; + Np->inout_p++; + } + + if (len == 0) + return -1; /* No valid roman numerals. */ + + /* Check for truncation. */ + if (truncated) + { + ereport(WARNING, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("Input truncated to \"%.*s\"", + len, romanChars))); + } Output after change: postgres=# SELECT to_number('MMXX ', 'RN'); WARNING: Input truncated to "MMXX" to_number ----------- 2020 (1 row) postgres=# SELECT to_number(' XIV ', ' RN'); WARNING: Input truncated to "XIV" to_number ----------- 14 (1 row) postgres=# SELECT to_number('M CC', 'RN'); WARNING: Input truncated to "M" to_number ----------- 1000 (1 row) Also, some modifications to the test cases will be required if we go with these changes. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2025-01-20T16:25:05Z
Hunaid Sohail <hunaidpgml@gmail.com> writes: > On Sat, Jan 18, 2025 at 5:27 AM Tom Lane <tgl@sss.pgh.pa.us> wrote: > Initially, when I looked at the test case: > SELECT to_number('M CC', 'RN'); > I was confused about whether it should be 'MCC'. After further inspection, > I realized that the output is 1000 for 'M'. The format of the input can be a > bit unclear. Perhaps we could add a note in the documentation > or issue a warning in roman_to_int function when input is truncated, > to clarify this behavior. I don't think a warning is a great idea at all. There is no other place in formatting.c that issues warnings, and this doesn't seem like the place to start. As an example, regression=# select to_number('123garbage', '999999'); to_number ----------- 123 (1 row) There's certainly a case that could be made that to_number should be stricter about trailing garbage, but it's probably a couple decades too late to change now. In any case it seems completely inappropriate to me for RN to adopt that policy all by itself. A different way that we could potentially look at this example is that RN should be willing to skip embedded spaces, leading to 'M CC' producing 1200 not 1000. There is a little bit of support for that idea in the existing behavior regression=# select to_number('123 456', '999999'); to_number ----------- 123456 (1 row) However, when you poke at that a bit closer, it's not a license for unlimited whitespace: regression=# select to_number('123 456', '999999'); to_number ----------- 12345 (1 row) I've not tracked down the exact cause of that, but I think it has to do with the fact that NUM_numpart_from_char() is willing to eat a single leading space per call, even if it's not the first call. The original author's reasoning for that is lost to history thanks to the lack of comments, but I believe that the idea was not "eat random whitespace" but "consume a space that was emitted as a substitute for a plus sign". The fact that it can happen once per '9' code feels more like a bug than something intentional. I'm not proposing that we do something about that, at least not today, but it doesn't seem like something we want to model RN's behavior on either. So I'm not in favor of allowing embedded spaces. However ... in poking at this, I noticed that I had been mis-understanding what to_char(..., 'RN') does: it fills to 15 characters with *leading* spaces not trailing spaces as I'd been thinking: regression=# select to_char(433, '|RN|'); to_char ------------------- | CDXXXIII| (1 row) So on the argument that to_number's RN should be willing to consume what to_char's RN produces, we're both wrong and roman_to_int should be willing to eat leading spaces. What do you think? regards, tom lane -
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2025-01-20T21:16:35Z
I wrote: > However, when you poke at that a bit closer, it's not a license > for unlimited whitespace: > regression=# select to_number('123 456', '999999'); > to_number > ----------- > 12345 > (1 row) > I've not tracked down the exact cause of that, but I think it > has to do with the fact that NUM_numpart_from_char() is willing > to eat a single leading space per call, even if it's not the > first call. I tried simply removing that bit: diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 3960235e14..366430863f 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -5134,12 +5134,6 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???"); #endif - if (OVERLOAD_TEST) - return; - - if (*Np->inout_p == ' ') - Np->inout_p++; - if (OVERLOAD_TEST) return; All our regression tests still pass, and this example seems to behave more sanely: regression=# select to_number('123 456', '999999'); to_number ----------- 12345 (1 row) regression=# select to_number('123 456', '999999'); to_number ----------- 1234 (1 row) That might or might not be a behavior you like, but it's at least possible to see where it's coming from: it's eating the digits that appear within a six-character window, and not any more. Not sure if anyone would thank us for making this change though. I can't avoid the suspicion that somebody somewhere is depending on the current behavior. Anyway, this is getting off-topic for the current thread. regards, tom lane -
Re: [PATCH] Add roman support for to_number function
Maciek Sakrejda <m.sakrejda@gmail.com> — 2025-01-21T00:18:44Z
V7 passes check-world here. But, just for kicks, I generated all possible 7-character sequences of Roman digits [1] to confirm whether everything either parsed cleanly or errored cleanly. Reviewing the output, I noticed that to_number accepts some dubiously-formatted values: postgres=# select to_number('mmmdcm', 'RN'); to_number ----------- 4400 (1 row) I'm assuming this was not intended, since the function comment notes the result will be in the 1-3999 range. (And to_char fails to parse this, failing the round-trip test.) Thanks, Maciek [1]: with rd(d) as (VALUES('i'),('v'),('x'),('l'),('c'),('d'),('m')), rn as (select d1.d || d2.d || d3.d || d4.d || d5.d || d6.d || d7.d as n from rd d1, rd d2, rd d3, rd d4, rd d5, rd d6, rd d7) select 'select to_number(' || rn.n || ', ''RN'');' from rn; -
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2025-01-21T01:41:25Z
Maciek Sakrejda <m.sakrejda@gmail.com> writes: > V7 passes check-world here. But, just for kicks, I generated all > possible 7-character sequences of Roman digits [1] to confirm whether > everything either parsed cleanly or errored cleanly. Reviewing the > output, I noticed that to_number accepts some dubiously-formatted > values: > postgres=# select to_number('mmmdcm', 'RN'); > to_number > ----------- > 4400 > (1 row) Ugh. This makes more urgent my question about where roman_to_int's algorithm came from, because there's evidently something not right about it. regards, tom lane -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2025-01-21T08:35:47Z
Hi, On Mon, Jan 20, 2025 at 9:25 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > I've not tracked down the exact cause of that, but I think it > has to do with the fact that NUM_numpart_from_char() is willing > to eat a single leading space per call, even if it's not the > first call. The original author's reasoning for that is lost > to history thanks to the lack of comments, but I believe that > the idea was not "eat random whitespace" but "consume a space > that was emitted as a substitute for a plus sign". The fact > that it can happen once per '9' code feels more like a bug than > something intentional. I'm not proposing that we do something > about that, at least not today, but it doesn't seem like > something we want to model RN's behavior on either. So I'm > not in favor of allowing embedded spaces. > Agreed. We should not allow trailing and embedded spaces. Since, trailing spaces and become embedded spaces like 'MCC ' or 'M CC'. It means cases like these should be invalid: SELECT to_number('MMXX ', 'RN'); SELECT to_number(' XIV ', ' RN'); SELECT to_number('M CC', 'RN'); > So on the argument that to_number's RN should be willing to > consume what to_char's RN produces, we're both wrong and > roman_to_int should be willing to eat leading spaces. > What do you think? > Agreed. Your changes in v7 consumes leading spaces if leading space is present in format (' RN'). But we need it to work on cases like: SELECT to_number(' XIV', 'RN'); So, I can add this logic in my next patch. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2025-01-21T08:45:12Z
Hi, On Tue, Jan 21, 2025 at 5:19 AM Maciek Sakrejda <m.sakrejda@gmail.com> wrote: > V7 passes check-world here. But, just for kicks, I generated all > possible 7-character sequences of Roman digits [1] to confirm whether > everything either parsed cleanly or errored cleanly. Reviewing the > output, I noticed that to_number accepts some dubiously-formatted > values: > > postgres=# select to_number('mmmdcm', 'RN'); > to_number > ----------- > 4400 > (1 row) > > I'm assuming this was not intended, since the function comment notes > the result will be in the 1-3999 range. (And to_char fails to parse > this, failing the round-trip test.) > > Thanks, > Maciek > > [1]: with rd(d) as (VALUES('i'),('v'),('x'),('l'),('c'),('d'),('m')), > rn as (select d1.d || d2.d || d3.d || d4.d || d5.d || d6.d || d7.d as > n from rd d1, rd d2, rd d3, rd d4, rd d5, rd d6, rd d7) select 'select > to_number(' || rn.n || ', ''RN'');' from rn; > Thanks for checking more cases. I feel that I found the source of the issue. It turns out I missed the rule that V, L, and D cannot appear before a larger numeral. As a result, cases like the following are also invalid: SELECT to_number('VIX', 'RN'); SELECT to_number('LXC', 'RN'); SELECT to_number('DCM', 'RN'); select to_number('MMDCM', 'RN'); select to_number('CLXC', 'RN'); I just need to add an if statement to handle these cases correctly. I will include the fix in the next patch, and also add these cases to the regression tests. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2025-01-21T09:26:12Z
On Tue, Jan 21, 2025 at 1:35 PM Hunaid Sohail <hunaidpgml@gmail.com> wrote: > Agreed. Your changes in v7 consumes leading spaces if leading space > is present in format (' RN'). But we need it to work on cases like: > SELECT to_number(' XIV', 'RN'); > So, I can add this logic in my next patch. > So, I was playing with leading spaces in v7 and found something interesting. postgres=# --both input and format both 2 spaces postgres=# SELECT to_number(' XIV', ' RN'); to_number ----------- 14 (1 row) postgres=# --input 1 space, format 2 spaces postgres=# --Input is read from "IV" ignoring "X" postgres=# SELECT to_number(' XIV', ' RN'); to_number ----------- 4 (1 row) postgres=# --should work after leading spaces are handled postgres=# SELECT to_number(' XIV', ' RN'); ERROR: invalid Roman numeral postgres=# select to_number('123456', ' 999999'); to_number ----------- 23456 (1 row) postgres=# select to_number('123456', ' 999999'); to_number ----------- 3456 (1 row) The leading spaces are consumed in the RN (from the main loop in Num_processor), and this behavior seems consistent with how simple numbers are handled. The Roman numeral parsing appears to start from where "RN" is in the format after leading spaces are consumed. Please review the first two examples of Roman numerals. I'd appreciate your opinions on whether this behavior should be considered valid. Regards, Hunaid Sohail -
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2025-01-21T15:48:56Z
Hunaid Sohail <hunaidpgml@gmail.com> writes: > The leading spaces are consumed in the RN (from the main loop > in Num_processor), and this behavior seems consistent with how > simple numbers are handled. The Roman numeral parsing > appears to start from where "RN" is in the format after > leading spaces are consumed. Yes, a space in the format string should consume a character from the input (whether it's a space or not). regression=# select to_number('x123', '999'); to_number ----------- 12 (1 row) regression=# select to_number('x123', ' 999'); to_number ----------- 123 (1 row) I used to think that a space in the format would consume any number of spaces from the input, but that doesn't seem to be true --- I think I was misled by that perhaps-bug in NUM_numpart_from_char. For example: regression=# select to_number(' 123', ' 999'); to_number ----------- 12 (1 row) One of the three input spaces is eaten by the format space, and one is taken as the sign, and then the 9's match ' 12'. (I don't think we should be expecting a sign in RN though.) However, as we add more input spaces: regression=# select to_number(' 123', ' 999'); to_number ----------- 12 (1 row) regression=# select to_number(' 123', ' 999'); to_number ----------- 1 (1 row) This is bizarrely inconsistent, and I think what's causing it is the extra space-consumption in NUM_numpart_from_char. regards, tom lane -
Re: [PATCH] Add roman support for to_number function
Hunaid Sohail <hunaidpgml@gmail.com> — 2025-01-22T13:33:48Z
Hi, I have attached a new patch v8 with the following changes: 1. Fixed cases reported by Maciek. 2. Handles leading spaces in input string. I have also added a few more negative tests after Maciek reported a few cases. I have also updated the format in the round trip test: ...to_char(i, 'FMRN') ... to ...to_char(i, 'RN') ... which verifies that leading spaces are now handled in input string with simple 'RN' when used with to_number. Looking forward to your feedback. Regards, Hunaid Sohail
-
Re: [PATCH] Add roman support for to_number function
Tom Lane <tgl@sss.pgh.pa.us> — 2025-01-22T20:29:04Z
Hunaid Sohail <hunaidpgml@gmail.com> writes: > I have attached a new patch v8 with the following changes: > 1. Fixed cases reported by Maciek. > 2. Handles leading spaces in input string. I pushed this after fooling with it a bit more: * The way you did the leading-space skip would actually skip anything whatsoever until it found a valid roman character. I don't think that's what's wanted here. We just want to skip whitespace --- the idea more or less is to consume leading whitespace that to_char('RN') might have emitted. * You'd also re-introduced failure on trailing whitespace (or indeed trailing anything), which I still don't agree with. It's not appropriate for RN to dictate that nothing can follow it. There's a separate discussion to be had about whether to_number is too lax about trailing garbage, but the policy should not be different for RN than it is for other format codes. * I made some other cosmetic changes such as rearranging the error checks into an order that made more sense to me. Thanks for submitting this patch! regards, tom lane