Skip to content

Commit a734d83

Browse files
author
Nikita Glukhov
committed
Add numeric transform for plpython
1 parent 3680cd0 commit a734d83

File tree

6 files changed

+460
-52
lines changed

6 files changed

+460
-52
lines changed

contrib/jsonb_plpython/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# contrib/jsonb_plpython/Makefile
22

33
MODULE_big = jsonb_plpython$(python_majorversion)
4-
OBJS = jsonb_plpython.o jsonb_lazy.o $(WIN32RES)
4+
OBJS = jsonb_plpython.o jsonb_lazy.o numeric_plpython.o $(WIN32RES)
55
PGFILEDESC = "jsonb_plpython - transform between jsonb and plpythonu"
66

77
PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) -DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"'

contrib/jsonb_plpython/jsonb_plpython.c

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "plpy_main.h"
66
#include "plpy_typeio.h"
77
#include "jsonb_plpython.h"
8+
#include "numeric_plpython.h"
89
#include "utils/jsonb.h"
910
#include "utils/fmgrprotos.h"
1011
#include "utils/numeric.h"
@@ -13,8 +14,11 @@ PG_MODULE_MAGIC;
1314

1415
void _PG_init(void);
1516

16-
typedef void (*PLy_elog_impl_t) (int elevel, const char *fmt,...);
17-
static PLy_elog_impl_t PLy_elog_impl_p;
17+
PLyObject_AsString_t PLyObject_AsString_p;
18+
PLy_elog_impl_t PLy_elog_impl_p;
19+
#if PY_MAJOR_VERSION >= 3
20+
PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
21+
#endif
1822

1923
PLy_get_global_memory_context_t PLy_get_global_memory_context_p;
2024
PLyObject_AsString_t PLyObject_AsString_p;
@@ -37,12 +41,6 @@ static JsonbValue *PLyObject_ToJsonbValue(PyObject *obj,
3741
PLyJsonb_FromJsonbContainer(jbc, len)
3842
#endif
3943

40-
#if PY_MAJOR_VERSION >= 3
41-
typedef PyObject *(*PLyUnicode_FromStringAndSize_t)
42-
(const char *s, Py_ssize_t size);
43-
static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
44-
#endif
45-
4644
/*
4745
* Module initialize function: fetch function pointers for cross-module calls.
4846
*/
@@ -134,6 +132,7 @@ PLyObject_FromJsonbValue(JsonbValue *jsonbValue)
134132
#endif
135133
return PyInt_FromLong((long) intval);
136134

135+
return PLyObject_FromNumeric(jsonbValue->val.numeric);
137136
num = NumericGetDatum(jsonbValue->val.numeric);
138137
str = DatumGetCString(DirectFunctionCall1(numeric_out, num));
139138

@@ -415,60 +414,19 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
415414
static JsonbValue *
416415
PLyNumber_ToJsonbValue(PyObject *obj, JsonbValue *jbvNum)
417416
{
418-
Numeric num;
419-
char *str;
420-
421417
jbvNum->type = jbvNumeric;
422-
423-
if (PyInt_Check(obj))
424-
{
425-
long val = PyInt_AsLong(obj);
426-
427-
if (val != -1 || !PyErr_Occurred())
428-
{
429-
jbvNum->val.numeric =
430-
DatumGetNumeric(DirectFunctionCall1(int8_numeric,
431-
Int64GetDatum((int64) val)));
432-
return jbvNum;
433-
}
434-
435-
PyErr_Clear();
436-
}
437-
438-
str = PLyObject_AsString(obj);
439-
440-
PG_TRY();
441-
{
442-
Datum numd;
443-
444-
numd = DirectFunctionCall3(numeric_in,
445-
CStringGetDatum(str),
446-
ObjectIdGetDatum(InvalidOid),
447-
Int32GetDatum(-1));
448-
num = DatumGetNumeric(numd);
449-
}
450-
PG_CATCH();
451-
{
452-
ereport(ERROR,
453-
(errcode(ERRCODE_DATATYPE_MISMATCH),
454-
(errmsg("could not convert value \"%s\" to jsonb", str))));
455-
}
456-
PG_END_TRY();
457-
458-
pfree(str);
418+
jbvNum->val.numeric = PLyNumber_ToNumeric(obj);
459419

460420
/*
461421
* jsonb doesn't allow NaN (per JSON specification), so we have to prevent
462422
* it here explicitly. (Infinity is also not allowed in jsonb, but
463423
* numeric_in above already catches that.)
464424
*/
465-
if (numeric_is_nan(num))
425+
if (numeric_is_nan(jbvNum->val.numeric))
466426
ereport(ERROR,
467427
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
468428
(errmsg("cannot convert NaN to jsonb"))));
469429

470-
jbvNum->val.numeric = num;
471-
472430
return jbvNum;
473431
}
474432

contrib/jsonb_plpython/jsonb_plpython.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "postgres.h"
22
#include "plpython.h"
33
#include "utils/jsonb.h"
4+
#include "plpy_typeio.h"
45

56
/* Python wrapper for jsonb container */
67
typedef struct PLyJsonb
@@ -33,6 +34,19 @@ extern void PLyKey_ToJsonbValue(PyObject *key, JsonbValue *jbv);
3334
extern PyObject *PLyObject_FromJsonbContainer(JsonbContainer *jsonb);
3435
extern PyObject *PLyObject_FromJsonbValue(JsonbValue *jsonbValue);
3536

37+
/* for PLyObject_AsString in plpy_typeio.c */
38+
typedef char *(*PLyObject_AsString_t) (PyObject *plrv);
39+
extern PLyObject_AsString_t PLyObject_AsString_p;
40+
41+
typedef void (*PLy_elog_impl_t) (int elevel, const char *fmt,...);
42+
extern PLy_elog_impl_t PLy_elog_impl_p;
43+
44+
#if PY_MAJOR_VERSION >= 3
45+
typedef PyObject *(*PLyUnicode_FromStringAndSize_t)
46+
(const char *s, Py_ssize_t size);
47+
extern PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
48+
#endif
49+
3650
typedef MemoryContext (*PLy_get_global_memory_context_t) (void);
3751
extern PLy_get_global_memory_context_t PLy_get_global_memory_context_p;
3852

contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,16 @@ CREATE TRANSFORM FOR jsonb LANGUAGE plpythonu (
1717
);
1818

1919
COMMENT ON TRANSFORM FOR jsonb LANGUAGE plpythonu IS 'transform between jsonb and Python';
20+
21+
CREATE FUNCTION numeric_to_plpython(val internal) RETURNS internal
22+
LANGUAGE C STRICT IMMUTABLE
23+
AS 'MODULE_PATHNAME';
24+
25+
CREATE FUNCTION plpython_to_numeric(val internal) RETURNS numeric
26+
LANGUAGE C STRICT IMMUTABLE
27+
AS 'MODULE_PATHNAME';
28+
29+
CREATE TRANSFORM FOR numeric LANGUAGE plpythonu (
30+
FROM SQL WITH FUNCTION numeric_to_plpython(internal),
31+
TO SQL WITH FUNCTION plpython_to_numeric(internal)
32+
);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy