Npgsql: Money handler doesn't respect the server currency format

Created on 26 Aug 2019  路  4Comments  路  Source: npgsql/npgsql

When I ran the test suite in lc_monetary = 'Japanise_Japan.932', following errors occured.

[excerpt]

 X GetUpdateCommandInfersParametersWithNpgsqDbType [303ms]
  error message:
     Expected: 123.40000000000001d
  But was:  1.23m

  stack trace:
     place Npgsql.Tests.CommandBuilderTests.GetUpdateCommandInfersParametersWithNpgsqDbType() 鍫存墍 C:\Users\k5user\source\repos\npgsql\test\Npgsql.Tests\CommandBuilderTests.cs:line 805

X Read("1.22::money",1.22m) [9ms]
  error message:
     Expected and actual are both <System.Int32[4]>
  Values differ at index [0]
  Expected: 122
  But was:  1

  stack trace:
     place Npgsql.Tests.Types.MoneyTests.Read(String query, Decimal expected) 鍫存墍 C:\Users\k5user\source\repos\npgsql\test\Npgsql.Tests\Types\MoneyTests.cs: line 30

  X Write("1.22::money",1.22m) [5ms]
  error message:
     Expected: True
  But was:  False

  stack trace:
     place Npgsql.Tests.Types.MoneyTests.Write(String query, Decimal expected) 鍫存墍 C:\Users\k5user\source\repos\npgsql\test\Npgsql.Tests\Types\MoneyTests.cs:line 45
etc...

_Originally posted by @GIriver in https://github.com/npgsql/npgsql/pull/2582#issuecomment-524679456_

bug

Most helpful comment

I examine this issue.

Problem

MoneyHandler in Npgsql has const int MoneyScale = 2, but the number of digits after the decimal point is different by lc_monetary in PostgreSQL data type money(ex. ja_JP: digit=0 123, en_US: digit=2 123.45).

So when using lc_monetary whose number of digits after the decimal point is not equal to two, MoneyHandler returns incorrect number.

All 4 comments

I examine this issue.

Problem

MoneyHandler in Npgsql has const int MoneyScale = 2, but the number of digits after the decimal point is different by lc_monetary in PostgreSQL data type money(ex. ja_JP: digit=0 123, en_US: digit=2 123.45).

So when using lc_monetary whose number of digits after the decimal point is not equal to two, MoneyHandler returns incorrect number.

Thanks @GIriver! This is the first time that I see that a locale setting influences binary wire encoding in PostgreSQL...

Do you know if there's any way of knowing the scale from the locale value in lc_monetary? Or is the only option here to set up a table on our side?

Note: in theory we could simply send a cast from some number to money and examine the results. This could be done at first connection to a database for yet-unknown locales in lc_monetary, but it's pretty awful...

Sorry, I still don't come up with idea to solve this issue.

PostgreSQL gets the number of digits after the decimal point by using setlocale(), localeconv() and lconv->frac_digits(include locale.h). (ref https://doxygen.postgresql.org/cash_8c.html#a99c28c4652e488c10c3541962246d12f)

However, I don't know the way Npgsql gets PostgreSQL's money scale.

As you said, sending a money to PostgreSQL and recieving the money from PostgreSQL is the way to know money scale...

Was this page helpful?
0 / 5 - 0 ratings