Thread: Getting a primitive numeric value from "DatumGetNumeric"?
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
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
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
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
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
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