Skip to content

Commit 36058a3

Browse files
committed
Create contrib/bool_plperl to provide a bool transform for PL/Perl[U].
plperl's default handling of bool arguments or results is not terribly satisfactory, since Perl doesn't consider the string 'f' to be false. Ideally we'd just fix that, but the backwards-compatibility hazard would be substantial. Instead, build a TRANSFORM module that can be optionally applied to provide saner semantics. Perhaps usefully, this is also about the minimum possible skeletal example of a plperl transform module; so it might be a better starting point for user-written transform modules than hstore_plperl or jsonb_plperl. Ivan Panchenko Discussion: https://postgr.es/m/[email protected]
1 parent a652558 commit 36058a3

14 files changed

+502
-4
lines changed

contrib/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ ALWAYS_SUBDIRS += sepgsql
7575
endif
7676

7777
ifeq ($(with_perl),yes)
78-
SUBDIRS += hstore_plperl jsonb_plperl
78+
SUBDIRS += bool_plperl hstore_plperl jsonb_plperl
7979
else
80-
ALWAYS_SUBDIRS += hstore_plperl jsonb_plperl
80+
ALWAYS_SUBDIRS += bool_plperl hstore_plperl jsonb_plperl
8181
endif
8282

8383
ifeq ($(with_python),yes)

contrib/bool_plperl/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated subdirectories
2+
/log/
3+
/results/
4+
/tmp_check/

contrib/bool_plperl/Makefile

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# contrib/bool_plperl/Makefile
2+
3+
MODULE_big = bool_plperl
4+
OBJS = \
5+
$(WIN32RES) \
6+
bool_plperl.o
7+
PGFILEDESC = "bool_plperl - bool transform for plperl"
8+
9+
PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plperl
10+
11+
EXTENSION = bool_plperlu bool_plperl
12+
DATA = bool_plperlu--1.0.sql bool_plperl--1.0.sql
13+
14+
REGRESS = bool_plperl bool_plperlu
15+
16+
ifdef USE_PGXS
17+
PG_CONFIG = pg_config
18+
PGXS := $(shell $(PG_CONFIG) --pgxs)
19+
include $(PGXS)
20+
else
21+
subdir = contrib/bool_plperl
22+
top_builddir = ../..
23+
include $(top_builddir)/src/Makefile.global
24+
include $(top_srcdir)/contrib/contrib-global.mk
25+
endif
26+
27+
# We must link libperl explicitly
28+
ifeq ($(PORTNAME), win32)
29+
# these settings are the same as for plperl
30+
override CPPFLAGS += -DPLPERL_HAVE_UID_GID -Wno-comment
31+
# ... see silliness in plperl Makefile ...
32+
SHLIB_LINK_INTERNAL += $(sort $(wildcard ../../src/pl/plperl/libperl*.a))
33+
else
34+
rpathdir = $(perl_archlibexp)/CORE
35+
SHLIB_LINK += $(perl_embed_ldflags)
36+
endif
37+
38+
# As with plperl we need to include the perl_includespec directory last.
39+
override CPPFLAGS := $(CPPFLAGS) $(perl_embed_ccflags) $(perl_includespec)
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* contrib/bool_plperl/bool_plperl--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION bool_plperl" to load this file. \quit
5+
6+
CREATE FUNCTION bool_to_plperl(val internal) RETURNS internal
7+
LANGUAGE C STRICT IMMUTABLE
8+
AS 'MODULE_PATHNAME';
9+
10+
CREATE FUNCTION plperl_to_bool(val internal) RETURNS bool
11+
LANGUAGE C STRICT IMMUTABLE
12+
AS 'MODULE_PATHNAME';
13+
14+
CREATE TRANSFORM FOR bool LANGUAGE plperl (
15+
FROM SQL WITH FUNCTION bool_to_plperl(internal),
16+
TO SQL WITH FUNCTION plperl_to_bool(internal)
17+
);
18+
19+
COMMENT ON TRANSFORM FOR bool LANGUAGE plperl IS 'transform between bool and Perl';

contrib/bool_plperl/bool_plperl.c

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "postgres.h"
2+
3+
#include "fmgr.h"
4+
#include "plperl.h"
5+
6+
7+
PG_MODULE_MAGIC;
8+
9+
PG_FUNCTION_INFO_V1(bool_to_plperl);
10+
11+
Datum
12+
bool_to_plperl(PG_FUNCTION_ARGS)
13+
{
14+
dTHX;
15+
bool in = PG_GETARG_BOOL(0);
16+
17+
return PointerGetDatum(in ? &PL_sv_yes : &PL_sv_no);
18+
}
19+
20+
21+
PG_FUNCTION_INFO_V1(plperl_to_bool);
22+
23+
Datum
24+
plperl_to_bool(PG_FUNCTION_ARGS)
25+
{
26+
dTHX;
27+
SV *in = (SV *) PG_GETARG_POINTER(0);
28+
29+
PG_RETURN_BOOL(SvTRUE(in));
30+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# bool_plperl extension
2+
comment = 'transform between bool and plperl'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/bool_plperl'
5+
relocatable = true
6+
trusted = true
7+
requires = 'plperl'
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* contrib/bool_plperl/bool_plperlu--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION bool_plperlu" to load this file. \quit
5+
6+
CREATE FUNCTION bool_to_plperlu(val internal) RETURNS internal
7+
LANGUAGE C STRICT IMMUTABLE
8+
AS 'MODULE_PATHNAME', 'bool_to_plperl';
9+
10+
CREATE FUNCTION plperlu_to_bool(val internal) RETURNS bool
11+
LANGUAGE C STRICT IMMUTABLE
12+
AS 'MODULE_PATHNAME', 'plperl_to_bool';
13+
14+
CREATE TRANSFORM FOR bool LANGUAGE plperlu (
15+
FROM SQL WITH FUNCTION bool_to_plperlu(internal),
16+
TO SQL WITH FUNCTION plperlu_to_bool(internal)
17+
);
18+
19+
COMMENT ON TRANSFORM FOR bool LANGUAGE plperlu IS 'transform between bool and Perl';
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# bool_plperlu extension
2+
comment = 'transform between bool and plperlu'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/bool_plperl'
5+
relocatable = true
6+
requires = 'plperlu'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
CREATE EXTENSION bool_plperl CASCADE;
2+
NOTICE: installing required extension "plperl"
3+
--- test transforming from perl
4+
CREATE FUNCTION perl2int(int) RETURNS bool
5+
LANGUAGE plperl
6+
TRANSFORM FOR TYPE bool
7+
AS $$
8+
return shift;
9+
$$;
10+
CREATE FUNCTION perl2text(text) RETURNS bool
11+
LANGUAGE plperl
12+
TRANSFORM FOR TYPE bool
13+
AS $$
14+
return shift;
15+
$$;
16+
CREATE FUNCTION perl2undef() RETURNS bool
17+
LANGUAGE plperl
18+
TRANSFORM FOR TYPE bool
19+
AS $$
20+
return undef;
21+
$$;
22+
SELECT perl2int(1);
23+
perl2int
24+
----------
25+
t
26+
(1 row)
27+
28+
SELECT perl2int(0);
29+
perl2int
30+
----------
31+
f
32+
(1 row)
33+
34+
SELECT perl2text('foo');
35+
perl2text
36+
-----------
37+
t
38+
(1 row)
39+
40+
SELECT perl2text('');
41+
perl2text
42+
-----------
43+
f
44+
(1 row)
45+
46+
SELECT perl2undef() IS NULL AS p;
47+
p
48+
---
49+
t
50+
(1 row)
51+
52+
--- test transforming to perl
53+
CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void
54+
LANGUAGE plperl
55+
TRANSFORM FOR TYPE bool
56+
AS $$
57+
my ($x, $y, $z) = @_;
58+
59+
die("NULL mistransformed") if (defined($z));
60+
die("TRUE mistransformed to UNDEF") if (!defined($x));
61+
die("FALSE mistransformed to UNDEF") if (!defined($y));
62+
die("TRUE mistransformed") if (!$x);
63+
die("FALSE mistransformed") if ($y);
64+
$$;
65+
SELECT bool2perl (true, false, NULL);
66+
bool2perl
67+
-----------
68+
69+
(1 row)
70+
71+
--- test selecting bool through SPI
72+
CREATE FUNCTION spi_test() RETURNS void
73+
LANGUAGE plperl
74+
TRANSFORM FOR TYPE bool
75+
AS $$
76+
my $rv = spi_exec_query('SELECT true t, false f, NULL n')->{rows}->[0];
77+
78+
die("TRUE mistransformed to UNDEF in SPI") if (!defined ($rv->{t}));
79+
die("FALSE mistransformed to UNDEF in SPI") if (!defined ($rv->{f}));
80+
die("NULL mistransformed in SPI") if (defined ($rv->{n}));
81+
die("TRUE mistransformed in SPI") if (!$rv->{t});
82+
die("FALSE mistransformed in SPI") if ($rv->{f});
83+
$$;
84+
SELECT spi_test();
85+
spi_test
86+
----------
87+
88+
(1 row)
89+
90+
DROP EXTENSION plperl CASCADE;
91+
NOTICE: drop cascades to 6 other objects
92+
DETAIL: drop cascades to function spi_test()
93+
drop cascades to extension bool_plperl
94+
drop cascades to function perl2int(integer)
95+
drop cascades to function perl2text(text)
96+
drop cascades to function perl2undef()
97+
drop cascades to function bool2perl(boolean,boolean,boolean)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
CREATE EXTENSION bool_plperlu CASCADE;
2+
NOTICE: installing required extension "plperlu"
3+
--- test transforming from perl
4+
CREATE FUNCTION perl2int(int) RETURNS bool
5+
LANGUAGE plperlu
6+
TRANSFORM FOR TYPE bool
7+
AS $$
8+
return shift;
9+
$$;
10+
CREATE FUNCTION perl2text(text) RETURNS bool
11+
LANGUAGE plperlu
12+
TRANSFORM FOR TYPE bool
13+
AS $$
14+
return shift;
15+
$$;
16+
CREATE FUNCTION perl2undef() RETURNS bool
17+
LANGUAGE plperlu
18+
TRANSFORM FOR TYPE bool
19+
AS $$
20+
return undef;
21+
$$;
22+
SELECT perl2int(1);
23+
perl2int
24+
----------
25+
t
26+
(1 row)
27+
28+
SELECT perl2int(0);
29+
perl2int
30+
----------
31+
f
32+
(1 row)
33+
34+
SELECT perl2text('foo');
35+
perl2text
36+
-----------
37+
t
38+
(1 row)
39+
40+
SELECT perl2text('');
41+
perl2text
42+
-----------
43+
f
44+
(1 row)
45+
46+
SELECT perl2undef() IS NULL AS p;
47+
p
48+
---
49+
t
50+
(1 row)
51+
52+
--- test transforming to perl
53+
CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void
54+
LANGUAGE plperlu
55+
TRANSFORM FOR TYPE bool
56+
AS $$
57+
my ($x, $y, $z) = @_;
58+
59+
die("NULL mistransformed") if (defined($z));
60+
die("TRUE mistransformed to UNDEF") if (!defined($x));
61+
die("FALSE mistransformed to UNDEF") if (!defined($y));
62+
die("TRUE mistransformed") if (!$x);
63+
die("FALSE mistransformed") if ($y);
64+
$$;
65+
SELECT bool2perl (true, false, NULL);
66+
bool2perl
67+
-----------
68+
69+
(1 row)
70+
71+
--- test selecting bool through SPI
72+
CREATE FUNCTION spi_test() RETURNS void
73+
LANGUAGE plperlu
74+
TRANSFORM FOR TYPE bool
75+
AS $$
76+
my $rv = spi_exec_query('SELECT true t, false f, NULL n')->{rows}->[0];
77+
78+
die("TRUE mistransformed to UNDEF in SPI") if (!defined ($rv->{t}));
79+
die("FALSE mistransformed to UNDEF in SPI") if (!defined ($rv->{f}));
80+
die("NULL mistransformed in SPI") if (defined ($rv->{n}));
81+
die("TRUE mistransformed in SPI") if (!$rv->{t});
82+
die("FALSE mistransformed in SPI") if ($rv->{f});
83+
$$;
84+
SELECT spi_test();
85+
spi_test
86+
----------
87+
88+
(1 row)
89+
90+
DROP EXTENSION plperlu CASCADE;
91+
NOTICE: drop cascades to 6 other objects
92+
DETAIL: drop cascades to function spi_test()
93+
drop cascades to extension bool_plperlu
94+
drop cascades to function perl2int(integer)
95+
drop cascades to function perl2text(text)
96+
drop cascades to function perl2undef()
97+
drop cascades to function bool2perl(boolean,boolean,boolean)

0 commit comments

Comments
 (0)