Thread: Getting a primitive numeric value from "DatumGetNumeric"?

Getting a primitive numeric value from "DatumGetNumeric"?

From
Demitri Muna
Date:
Hi,

I’m writing a C extension for PostgreSQL. One possible input datatype for my function is a numeric array, e.g.
ARRAY[[1.5,2.5],[3.5,4.5]].I can use “DatumGetNumeric” to extract a “Numeric” data type from the data, but at some
pointI need to convert this to a number (e.g. double) so that I can do mathy things with it. How does one convert a
“Numeric”to, say, a double? 

I have a workaround in that I can pass this to my function:

ARRAY[[1.5,2.5],[3.5,4.5]]::float8[]

but I’d rather have the code do that instead of bothering the user to remember that.

Thanks,
Demitri

Re: Getting a primitive numeric value from "DatumGetNumeric"?

From
Tom Lane
Date:
Demitri Muna <postgresql@demitri.com> writes:
> I’m writing a C extension for PostgreSQL. One possible input datatype for my function is a numeric array, e.g.
ARRAY[[1.5,2.5],[3.5,4.5]].I can use “DatumGetNumeric” to extract a “Numeric” data type from the data, but at some
pointI need to convert this to a number (e.g. double) so that I can do mathy things with it. How does one convert a
“Numeric”to, say, a double? 

If you want to work with doubles, why don't you declare the function as
taking doubles?

> I have a workaround in that I can pass this to my function:
> ARRAY[[1.5,2.5],[3.5,4.5]]::float8[]
> but I’d rather have the code do that instead of bothering the user to remember that.

Well, the implicit coercions work in your favor in this particular case.
You can just do, eg,

regression=# create function foo(float8[]) returns float8 as
regression-# 'select $1[1]' language sql;
CREATE FUNCTION
regression=# select foo(array[1.1,1.2]);
 foo
-----
 1.1
(1 row)

or to emphasize that it is doing a conversion:

regression=# select foo(array[1.1,1.2]::numeric[]);
 foo
-----
 1.1
(1 row)


            regards, tom lane


Re: Getting a primitive numeric value from "DatumGetNumeric"?

From
Demitri Muna
Date:
Hi Tom,

On Feb 20, 2018, at 10:54 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

> Well, the implicit coercions work in your favor in this particular case.

Ah, I wasn’t aware of implicit coercion. Yes, that solves the problem perfectly, thanks.

Out of curiosity, how does one read a numeric type from within a C extension (i.e. get a number value out of the Datum
type)?I ask as I was unable to find an example and there are a few open questions on Stack Overflow (e.g.
https://stackoverflow.com/questions/12588554/postgres-c-function-passing-returning-numerics).

Thanks,
Demitri



Re: Getting a primitive numeric value from "DatumGetNumeric"?

From
Michael Paquier
Date:
On Thu, Feb 22, 2018 at 08:00:45PM -0500, Demitri Muna wrote:
> Ah, I wasn’t aware of implicit coercion. Yes, that solves the problem perfectly, thanks.
>
> Out of curiosity, how does one read a numeric type from within a C
> extension (i.e. get a number value out of the Datum type)? I ask as I
> was unable to find an example and there are a few open questions on
> Stack Overflow
> (e.g. https://stackoverflow.com/questions/12588554/postgres-c-function-passing-returning-numerics).

PG_GETARG_NUMERIC(), no? When working on implementing your own data
types or when hacking out functions which manipulate arguments of an
existing datatype, looking at the input and output functions help a
lot.  In your case, numeric_in and numeric_out in
src/backend/utils/adt/numeric.c is full of hints.
--
Michael

Attachment

Re: Getting a primitive numeric value from "DatumGetNumeric"?

From
Tom Lane
Date:
Michael Paquier <michael@paquier.xyz> writes:
> On Thu, Feb 22, 2018 at 08:00:45PM -0500, Demitri Muna wrote:
>> Out of curiosity, how does one read a numeric type from within a C
>> extension (i.e. get a number value out of the Datum type)?

> PG_GETARG_NUMERIC(), no?

I think the core point here is that PG's "numeric" type *isn't* any
primitive C type; it's a variable-length BCD encoding.  If you want
to deal with it you can, but you must spend some time reading
src/backend/utils/adt/numeric.c, as Michael suggests.  If you just
want a convenient C approximation, then work with float8 and let
the implicit-coercion machinery do the conversion for you.

            regards, tom lane


Re: Getting a primitive numeric value from "DatumGetNumeric"?

From
Demitri Muna
Date:
Hi,

On Feb 22, 2018, at 9:31 PM, Michael Paquier <michael@paquier.xyz> wrote:

> PG_GETARG_NUMERIC(), no?

That function returns an object of datatype “Numeric” which still requires some (not immediately obvious) conversation
toa double (or whatever primitive C type). 

> When working on implementing your own data
> types or when hacking out functions which manipulate arguments of an
> existing datatype, looking at the input and output functions help a
> lot.  In your case, numeric_in and numeric_out in
> src/backend/utils/adt/numeric.c is full of hints.

I spent an hour diving into the code out of curiosity. I found useful functions like this:

double numeric_to_double_no_overflow(Numeric n)

They’re available from the PostgreSQL main source code, but not exposed in the public headers. (Maybe I was missing
something.)There was enough there where I could see a way to copy/paste or otherwise link to those methods, but as Tom
pointedout, implicit coercion handles what I need so I’ll stick with that. 

Cheers,
Demitri