Thread: BUG #12053: Strange behavior for numeric types with unspecified precision-scale

BUG #12053: Strange behavior for numeric types with unspecified precision-scale

From
tommaso.sala@cla-it.eu
Date:
The following bug has been logged on the website:

Bug reference:      12053
Logged by:          Tommaso Sala
Email address:      tommaso.sala@cla-it.eu
PostgreSQL version: 9.3.0
Operating system:   Windows Server 2008
Description:

We found out that PgSql acts weirdly when using "numeric" type with
UN-specified precision and scale
Writing 0.001 via a .net DataAdapter to a numeric column with unspecified
precision-scale results in a weird 0.00 value:
if you later
SELECT "that value" + 0.001 you get 0.002,
but if you
SELECT "that value" * 2 you get 0.00
and
SELECT "that value" * 5 gives a rounded 0.01
Value in the database is correct, since if you TO_CHAR it, it gets printed
correctly as .001, but if you SELECT it, you get 0.00
Also, the weirder thing is that 0.000001 doesn't get truncated!
Specifying precision and scale for that column, solves the issue.
Bug is described here:

http://stackoverflow.com/questions/27109361/writing-0-001-to-postgres-9-x-via-data-adapter-results-in-a-weird-0-00-value
tommaso.sala@cla-it.eu writes:
> We found out that PgSql acts weirdly when using "numeric" type with
> UN-specified precision and scale
> Writing 0.001 via a .net DataAdapter to a numeric column with unspecified
> precision-scale results in a weird 0.00 value:
> if you later
> SELECT "that value" + 0.001 you get 0.002,
> but if you
> SELECT "that value" * 2 you get 0.00
> and
> SELECT "that value" * 5 gives a rounded 0.01
> Value in the database is correct, since if you TO_CHAR it, it gets printed
> correctly as .001, but if you SELECT it, you get 0.00
> Also, the weirder thing is that 0.000001 doesn't get truncated!

I think you must have some issues with the .Net adapter.  Postgres
itself doesn't give such inconsistent results:

regression=# create table t1 (f1 numeric);
CREATE TABLE
regression=# insert into t1 values (0.001);
INSERT 0 1
regression=# select * from t1;
  f1
-------
 0.001
(1 row)

regression=# select f1 + 0.001 from t1;
 ?column?
----------
    0.002
(1 row)

regression=# select f1 * 2 from t1;
 ?column?
----------
    0.002
(1 row)

regression=# select f1 * 5 from t1;
 ?column?
----------
    0.005
(1 row)

            regards, tom lane
Tommaso Sala <tommaso.sala@cla-it.eu> writes:
> We found that it is probably a bug in the data adapter (supplied by Devart
> http://www.devart.com/).

> But, once that weird value is written in DB by Devart adapter, there must
> be some kind of strange behavior also in Postgres.
> In fact, reading that value causes strange results:

> postgres=# select "WEIRD_FIELD" from "TABLE";
>  WEIRD_FIELD
> ----------------
>            0.00
> (1 row)


> postgres=# select "WEIRD_FIELD" + 0.01 from "TABLE";
>  ?column?
> ----------
>      0.01
> (1 row)


> postgres=# select "WEIRD_FIELD" * 2 from "TABLE";
>  ?column?
> ----------
>      0.00
> (1 row)


> postgres=# select "WEIRD_FIELD" + 0.001 from "TABLE";
>  ?column?
> ----------
>     0.002
> (1 row)


> postgres=# select 1 / "WEIRD_FIELD" from "TABLE";
>        ?column?
> -----------------------
>  1000.0000000000000000
> (1 row)


> postgres=# select TO_CHAR("WEIRD_FIELD", 'FM99999999D99999999') from
> "TABLE";
>  to_char
> ---------
>  .001
> (1 row)

> It's always 0.001 but if selected or multiplicated it becomes 0.00.

That's pretty weird, but it's hard to debug without access to
Devart's adapter.  Can you trace what the adapter is doing when
it inserts this value?  (log_statement = all would help.)

An idea that comes to mind is that maybe Devart is using binary
parameters and transmitting a value that isn't 100% legal; but
that's only a guess at this stage.  (It does look like numeric_recv
is pretty trusting about the input weight and dscale fields;
I'm not sure if a bad dscale would explain these symptoms, but
it seems possible.)

            regards, tom lane
We found that it is probably a bug in the data adapter (supplied by Devart
http://www.devart.com/).

But, once that weird value is written in DB by Devart adapter, there must
be some kind of strange behavior also in Postgres.
In fact, reading that value causes strange results:

postgres=3D# select "WEIRD_FIELD" from "TABLE";
 WEIRD_FIELD
----------------
           0.00
(1 row)


postgres=3D# select "WEIRD_FIELD" + 0.01 from "TABLE";
 ?column?
----------
     0.01
(1 row)


postgres=3D# select "WEIRD_FIELD" * 2 from "TABLE";
 ?column?
----------
     0.00
(1 row)


postgres=3D# select "WEIRD_FIELD" + 0.001 from "TABLE";
 ?column?
----------
    0.002
(1 row)


postgres=3D# select 1 / "WEIRD_FIELD" from "TABLE";
       ?column?
-----------------------
 1000.0000000000000000
(1 row)


postgres=3D# select TO_CHAR("WEIRD_FIELD", 'FM99999999D99999999') from
"TABLE";
 to_char
---------
 .001
(1 row)

It's always 0.001 but if selected or multiplicated it becomes 0.00.

Repeat the queries after writing the same value via plain SQL:

postgres=3D# select "WEIRD_FIELD" from "TABLE";
 WEIRD_FIELD
----------------
          0.001
(1 row)


postgres=3D# select "WEIRD_FIELD" + 0.01 from "TABLE";
 ?column?
----------
    0.011
(1 row)


postgres=3D# select "WEIRD_FIELD" + 0.001 from "TABLE";
 ?column?
----------
    0.002
(1 row)


postgres=3D# select "WEIRD_FIELD" * 2 from "TABLE";
 ?column?
----------
    0.002
(1 row)


postgres=3D# select 1 / "WEIRD_FIELD" from "TABLE";
       ?column?
-----------------------
 1000.0000000000000000
(1 row)


postgres=3D# select TO_CHAR("WEIRD_FIELD", 'FM99999999D99999999') from
"TABLE";
 to_char
---------
 .001
(1 row)

You see it?






















*Tommaso Sala*
*Developer*
------------------------------

*Computer Line Associates*
www.cla-it.eu

Via della Viggioletta, 8
29121 Piacenza, Italy
tel. +39 (0523) 1865038



*Nota di riservatezza:* Il presente messaggio, corredato dei relativi
allegati, contiene informazioni da considerarsi strettamente riservate, ed
=C3=A8 destinato esclusivamente al destinatario sopra indicato, il quale =
=C3=A8
l'unico autorizzato ad usarlo, copiarlo e, sotto la propria responsabilit=
=C3=A0,
diffonderlo. Chiunque ricevesse questo messaggio per errore o comunque lo
leggesse senza esserne legittimato =C3=A8 avvertito che trattenerlo, copiar=
lo,
divulgarlo, distribuirlo a persone diverse dal destinatario =C3=A8 severame=
nte
proibito, ed =C3=A8 pregato di rinviarlo immediatamente al mittente
distruggendone l'originale. Grazie.

*Confidentiality notice:* This message, together with its attachments,
contains strictly confidential information and is intended only for the
addressee identified above, who is the sole party authorized to use and
copy it and, assuming any related liability, to forward it to
others. Anyone receiving this message by mistake or reading it without
authorization is hereby notified that storage, reproduction, disclosure
or distribution of the message to persons other than the addressee is
strictly forbidden. They are asked to return the message immediately to the
sender and to erase the original message received. Thank you.

*  Save a tree! Don't print this e-mail unless you really need to.*

2014-11-26 16:50 GMT+01:00 Tom Lane <tgl@sss.pgh.pa.us>:

> tommaso.sala@cla-it.eu writes:
> > We found out that PgSql acts weirdly when using "numeric" type with
> > UN-specified precision and scale
> > Writing 0.001 via a .net DataAdapter to a numeric column with unspecifi=
ed
> > precision-scale results in a weird 0.00 value:
> > if you later
> > SELECT "that value" + 0.001 you get 0.002,
> > but if you
> > SELECT "that value" * 2 you get 0.00
> > and
> > SELECT "that value" * 5 gives a rounded 0.01
> > Value in the database is correct, since if you TO_CHAR it, it gets
> printed
> > correctly as .001, but if you SELECT it, you get 0.00
> > Also, the weirder thing is that 0.000001 doesn't get truncated!
>
> I think you must have some issues with the .Net adapter.  Postgres
> itself doesn't give such inconsistent results:
>
> regression=3D# create table t1 (f1 numeric);
> CREATE TABLE
> regression=3D# insert into t1 values (0.001);
> INSERT 0 1
> regression=3D# select * from t1;
>   f1
> -------
>  0.001
> (1 row)
>
> regression=3D# select f1 + 0.001 from t1;
>  ?column?
> ----------
>     0.002
> (1 row)
>
> regression=3D# select f1 * 2 from t1;
>  ?column?
> ----------
>     0.002
> (1 row)
>
> regression=3D# select f1 * 5 from t1;
>  ?column?
> ----------
>     0.005
> (1 row)
>
>                         regards, tom lane
>
Hi, I already tried to log all, but it seems not to help a lot.

In the StackOverflow question I originally linked in this bug report, I
wrote the following:

   >  log_statement =3D 'all' gives a weirdER result:
   >
   >  UPDATE "TABLE" SET ... "WEIRD_FIELD"=3D$8 ... WHERE ...
   >
   >  DETAIL:  parameters: $1 =3D '7', $2 =3D '7', $3 =3D '18', $4 =3D '18'=
, $5 =3D
'V03', $6 =3D 'Hz',
   >                       $7 =3D 'Hz', $8 =3D '0.00', $9 =3D '0', $10 =3D =
'2', $11
=3D '0'
   >
   >  The parameter for the weird field is printed as zero (0.00), but
clearly it is not...

As you told, Postgres probably accept and store a non-100%-legal value,
rather than throwing an exception,
but it seems difficult to understand something from the plain-text log.

If I could any help you, please tell me.







*Tommaso Sala*
*Developer*
------------------------------

*Computer Line Associates*
www.cla-it.eu

Via della Viggioletta, 8
29121 Piacenza, Italy
tel. +39 (0523) 1865038



*Nota di riservatezza:* Il presente messaggio, corredato dei relativi
allegati, contiene informazioni da considerarsi strettamente riservate, ed
=C3=A8 destinato esclusivamente al destinatario sopra indicato, il quale =
=C3=A8
l'unico autorizzato ad usarlo, copiarlo e, sotto la propria responsabilit=
=C3=A0,
diffonderlo. Chiunque ricevesse questo messaggio per errore o comunque lo
leggesse senza esserne legittimato =C3=A8 avvertito che trattenerlo, copiar=
lo,
divulgarlo, distribuirlo a persone diverse dal destinatario =C3=A8 severame=
nte
proibito, ed =C3=A8 pregato di rinviarlo immediatamente al mittente
distruggendone l'originale. Grazie.

*Confidentiality notice:* This message, together with its attachments,
contains strictly confidential information and is intended only for the
addressee identified above, who is the sole party authorized to use and
copy it and, assuming any related liability, to forward it to
others. Anyone receiving this message by mistake or reading it without
authorization is hereby notified that storage, reproduction, disclosure
or distribution of the message to persons other than the addressee is
strictly forbidden. They are asked to return the message immediately to the
sender and to erase the original message received. Thank you.

*  Save a tree! Don't print this e-mail unless you really need to.*

2014-11-27 21:48 GMT+01:00 Tom Lane <tgl@sss.pgh.pa.us>:

> Tommaso Sala <tommaso.sala@cla-it.eu> writes:
> > We found that it is probably a bug in the data adapter (supplied by
> Devart
> > http://www.devart.com/).
>
> > But, once that weird value is written in DB by Devart adapter, there mu=
st
> > be some kind of strange behavior also in Postgres.
> > In fact, reading that value causes strange results:
>
> > postgres=3D# select "WEIRD_FIELD" from "TABLE";
> >  WEIRD_FIELD
> > ----------------
> >            0.00
> > (1 row)
>
>
> > postgres=3D# select "WEIRD_FIELD" + 0.01 from "TABLE";
> >  ?column?
> > ----------
> >      0.01
> > (1 row)
>
>
> > postgres=3D# select "WEIRD_FIELD" * 2 from "TABLE";
> >  ?column?
> > ----------
> >      0.00
> > (1 row)
>
>
> > postgres=3D# select "WEIRD_FIELD" + 0.001 from "TABLE";
> >  ?column?
> > ----------
> >     0.002
> > (1 row)
>
>
> > postgres=3D# select 1 / "WEIRD_FIELD" from "TABLE";
> >        ?column?
> > -----------------------
> >  1000.0000000000000000
> > (1 row)
>
>
> > postgres=3D# select TO_CHAR("WEIRD_FIELD", 'FM99999999D99999999') from
> > "TABLE";
> >  to_char
> > ---------
> >  .001
> > (1 row)
>
> > It's always 0.001 but if selected or multiplicated it becomes 0.00.
>
> That's pretty weird, but it's hard to debug without access to
> Devart's adapter.  Can you trace what the adapter is doing when
> it inserts this value?  (log_statement =3D all would help.)
>
> An idea that comes to mind is that maybe Devart is using binary
> parameters and transmitting a value that isn't 100% legal; but
> that's only a guess at this stage.  (It does look like numeric_recv
> is pretty trusting about the input weight and dscale fields;
> I'm not sure if a bad dscale would explain these symptoms, but
> it seems possible.)
>
>                         regards, tom lane
>
Tommaso Sala <tommaso.sala@cla-it.eu> writes:
> Hi, I already tried to log all, but it seems not to help a lot.
> In the StackOverflow question I originally linked in this bug report, I
> wrote the following:

>>>>> log_statement = 'all' gives a weirdER result:
>>>>>
>>>>> UPDATE "TABLE" SET ... "WEIRD_FIELD"=$8 ... WHERE ...
>>>>>
>>>>> DETAIL:  parameters: $1 = '7', $2 = '7', $3 = '18', $4 = '18', $5 = 'V03', $6 = 'Hz',
>>>>> $7 = 'Hz', $8 = '0.00', $9 = '0', $10 = '2', $11 = '0'

> The parameter for the weird field is printed as zero (0.00), but
> clearly it is not...

Ah, so you did have a parameterized statement and not just a plain-text
SQL command.  The log entry doesn't say whether the parameter value was
sent as text or binary, but if it had been sent as text, that would have
been exactly the string sent, and surely it'd have been read as plain old
zero.  If it had been sent as binary, this printout would be obtained the
same way as a regular "select *" would do, and we already know the bogus
value prints as 0.00 that way.

I did some experimentation and verified that if I manufacture a numeric
value that's really 0.001 but has dscale = 2, it will act precisely as
described in this report.  The commentary in numeric.c saith

 * dscale, or display scale, is the nominal precision expressed as number
 * of digits after the decimal point (it must always be >= 0 at present).
 * dscale may be more than the number of physically stored fractional digits,
 * implying that we have suppressed storage of significant trailing zeroes.
 * It should never be less than the number of stored digits, since that would
 * imply hiding digits that are present.

and that "hiding" is exactly what we're looking at.

So the question is whether it's worth adding logic to numeric_recv
to guard against bogus dscale values.  I think that detecting this
case would probably add a noticeable number of cycles to numeric_in.
(We can't just count the number of digits received, since (a) trailing
zeroes past dscale are OK, and (b) what we have at this point is
base-10000 digits not base-10 digits...)  I guess we're usually willing
to expend cycles to guard against client error, so maybe we should
do it here too.

            regards, tom lane
I wrote:
> So the question is whether it's worth adding logic to numeric_recv
> to guard against bogus dscale values.  I think that detecting this
> case would probably add a noticeable number of cycles to numeric_in.
> (We can't just count the number of digits received, since (a) trailing
> zeroes past dscale are OK, and (b) what we have at this point is
> base-10000 digits not base-10 digits...)  I guess we're usually willing
> to expend cycles to guard against client error, so maybe we should
> do it here too.

I had originally been thinking of throwing an error if the presented
dscale was too small for the number of digits sent, but after some
reflection it seems like it'd be safer to just silently truncate the
extra digits away.  If we throw an error it's likely to break applications
that are dependent on this buggy data adapter, and I'm not sure that the
users will thank us for that.  Truncating the extra digits will make the
value actually match what it would've printed as, and if we grant that the
Devart folk did any testing of their code at all, they probably looked at
what was printed and thought that that was what they intended.  That is,
I'm assuming that dscale = 2 means they only want 2 decimal places in
the value.

So I propose the attached patch, which requires only a minimal amount
of new code and is about as fast as we're going to get if we want to
check this issue at all.  (Note: the apparently new error condition
for out-of-range dscale doesn't create a backwards compatibility hazard,
because make_result would've barfed anyway.  This is just a more
to-the-point error message.)

            regards, tom lane

diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index d61af92..c73f9bc 100644
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
*************** numeric_recv(PG_FUNCTION_ARGS)
*** 717,722 ****
--- 717,724 ----
      alloc_var(&value, len);

      value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
+     /* we allow any int16 for weight --- OK? */
+
      value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
      if (!(value.sign == NUMERIC_POS ||
            value.sign == NUMERIC_NEG ||
*************** numeric_recv(PG_FUNCTION_ARGS)
*** 726,731 ****
--- 728,738 ----
                   errmsg("invalid sign in external \"numeric\" value")));

      value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
+     if ((value.dscale & NUMERIC_DSCALE_MASK) != value.dscale)
+         ereport(ERROR,
+                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                  errmsg("invalid scale in external \"numeric\" value")));
+
      for (i = 0; i < len; i++)
      {
          NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
*************** numeric_recv(PG_FUNCTION_ARGS)
*** 737,742 ****
--- 744,757 ----
          value.digits[i] = d;
      }

+     /*
+      * If the given dscale would hide any digits, truncate those digits away.
+      * We could alternatively throw an error, but that would take a bunch of
+      * extra code (about as much as trunc_var involves), and it might cause
+      * client compatibility issues.
+      */
+     trunc_var(&value, value.dscale);
+
      apply_typmod(&value, typmod);

      res = make_result(&value);

Tommaso Sala <tommaso.sala@cla-it.eu> writes:
> The strange fact is that if you try to write 0.000001, it gets displayed
> correctly

My guess is that the adapter miscomputes dscale in only some situations.

> I'd agree with your proposed solution, if I only set a dscale of 2.
> But I didn't.

You didn't, but the available evidence says that Devart's adapter did.

If you maintain there is some other bug involved, maybe I *should* make
numeric_recv throw an error, just so the blame gets placed clearly.

            regards, tom lane

Re: BUG #12053: Strange behavior for numeric types with unspecified precision-scale

From
David G Johnston
Date:
Tom Lane-2 wrote
> Tommaso Sala <

> tommaso.sala@

> > writes:
>> The strange fact is that if you try to write 0.000001, it gets displayed
>> correctly
>
> My guess is that the adapter miscomputes dscale in only some situations.
>
>> I'd agree with your proposed solution, if I only set a dscale of 2.
>> But I didn't.
>
> You didn't, but the available evidence says that Devart's adapter did.
>
> If you maintain there is some other bug involved, maybe I *should* make
> numeric_recv throw an error, just so the blame gets placed clearly.
>
>             regards, tom lane

Would there be value in back-patching the truncation option but making it
fail in 9.5?

I assume this is somehow a different situation than that where someone does,
for instance, (1.0/3.0)::numeric(5,2) or '1.0001':numeric(3,2)...neither of
these should fail.

David J.





--
View this message in context:
http://postgresql.nabble.com/BUG-12053-Strange-behavior-for-numeric-types-with-unspecified-precision-scale-tp5828340p5828655.html
Sent from the PostgreSQL - bugs mailing list archive at Nabble.com.
The strange fact is that if you try to write 0.000001, it gets displayed
correctly

I'd agree with your proposed solution, if I only set a dscale of 2.
But I didn't. The column type was set as just numeric.
The documentation for numeric says:

Specifying:

NUMERIC

without any precision or scale creates a column in which numeric values of
any precision and scale can be stored, up to the implementation limit on
precision. A column of this kind will not coerce input values to any
particular scale, whereas numeric columns with a declared scale will coerce
input values to that scale.

So I'd expect a "just numeric" column to contain almost everything!
And this is what I see for almost every value, but 0.001.
As I said before 0.000001 gets displayed correctly and 0.0009895846 do as
well!

*Tommaso Sala*
*Developer*
------------------------------

*Computer Line Associates*
www.cla-it.eu

Via della Viggioletta, 8
29121 Piacenza, Italy
tel. +39 (0523) 1865038



*Nota di riservatezza:* Il presente messaggio, corredato dei relativi
allegati, contiene informazioni da considerarsi strettamente riservate, ed
=C3=A8 destinato esclusivamente al destinatario sopra indicato, il quale =
=C3=A8
l'unico autorizzato ad usarlo, copiarlo e, sotto la propria responsabilit=
=C3=A0,
diffonderlo. Chiunque ricevesse questo messaggio per errore o comunque lo
leggesse senza esserne legittimato =C3=A8 avvertito che trattenerlo, copiar=
lo,
divulgarlo, distribuirlo a persone diverse dal destinatario =C3=A8 severame=
nte
proibito, ed =C3=A8 pregato di rinviarlo immediatamente al mittente
distruggendone l'originale. Grazie.

*Confidentiality notice:* This message, together with its attachments,
contains strictly confidential information and is intended only for the
addressee identified above, who is the sole party authorized to use and
copy it and, assuming any related liability, to forward it to
others. Anyone receiving this message by mistake or reading it without
authorization is hereby notified that storage, reproduction, disclosure
or distribution of the message to persons other than the addressee is
strictly forbidden. They are asked to return the message immediately to the
sender and to erase the original message received. Thank you.

Il giorno 29/nov/2014, alle ore 03:33, Tom Lane <tgl@sss.pgh.pa.us> ha
scritto:

I wrote:

So the question is whether it's worth adding logic to numeric_recv

to guard against bogus dscale values.  I think that detecting this

case would probably add a noticeable number of cycles to numeric_in.

(We can't just count the number of digits received, since (a) trailing

zeroes past dscale are OK, and (b) what we have at this point is

base-10000 digits not base-10 digits...)  I guess we're usually willing

to expend cycles to guard against client error, so maybe we should

do it here too.


I had originally been thinking of throwing an error if the presented
dscale was too small for the number of digits sent, but after some
reflection it seems like it'd be safer to just silently truncate the
extra digits away.  If we throw an error it's likely to break applications
that are dependent on this buggy data adapter, and I'm not sure that the
users will thank us for that.  Truncating the extra digits will make the
value actually match what it would've printed as, and if we grant that the
Devart folk did any testing of their code at all, they probably looked at
what was printed and thought that that was what they intended.  That is,
I'm assuming that dscale =3D 2 means they only want 2 decimal places in
the value.

So I propose the attached patch, which requires only a minimal amount
of new code and is about as fast as we're going to get if we want to
check this issue at all.  (Note: the apparently new error condition
for out-of-range dscale doesn't create a backwards compatibility hazard,
because make_result would've barfed anyway.  This is just a more
to-the-point error message.)

           regards, tom lane

diff --git a/src/backend/utils/adt/numeric.c
b/src/backend/utils/adt/numeric.c index d61af92..c73f9bc 100644 ***
a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c
*************** numeric_recv(PG_FUNCTION_ARGS) *** 717,722 **** --- 717,724
---- alloc_var(&value, len); value.weight =3D (int16) pq_getmsgint(buf,
sizeof(int16)); + /* we allow any int16 for weight --- OK? */ + value.sign
=3D (uint16) pq_getmsgint(buf, sizeof(uint16)); if (!(value.sign =3D=3D
NUMERIC_POS || value.sign =3D=3D NUMERIC_NEG || ***************
numeric_recv(PG_FUNCTION_ARGS) *** 726,731 **** --- 728,738 ----
errmsg("invalid sign in external \"numeric\" value"))); value.dscale =3D
(uint16) pq_getmsgint(buf, sizeof(uint16)); + if ((value.dscale &
NUMERIC_DSCALE_MASK) !=3D value.dscale) + ereport(ERROR, +
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid scale in
external \"numeric\" value"))); + for (i =3D 0; i < len; i++) { NumericDigi=
t
d =3D pq_getmsgint(buf, sizeof(NumericDigit)); ***************
numeric_recv(PG_FUNCTION_ARGS) *** 737,742 **** --- 744,757 ----
value.digits[i] =3D d; } + /* + * If the given dscale would hide any digits=
,
truncate those digits away. + * We could alternatively throw an error, but
that would take a bunch of + * extra code (about as much as trunc_var
involves), and it might cause + * client compatibility issues. + */ +
trunc_var(&value, value.dscale); + apply_typmod(&value, typmod); res =3D
make_result(&value);