diff --git a/contrib/Makefile b/contrib/Makefile
index 92184ed487..795f69cf64 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -75,9 +75,9 @@ ALWAYS_SUBDIRS += sepgsql
 endif
 
 ifeq ($(with_perl),yes)
-SUBDIRS += hstore_plperl jsonb_plperl
+SUBDIRS += hstore_plperl jsonb_plperl bool_plperl
 else
-ALWAYS_SUBDIRS += hstore_plperl jsonb_plperl
+ALWAYS_SUBDIRS += hstore_plperl jsonb_plperl bool_plperl
 endif
 
 ifeq ($(with_python),yes)
diff --git a/doc/src/sgml/plperl.sgml b/doc/src/sgml/plperl.sgml
index e4769c0e38..79f781a4ce 100644
--- a/doc/src/sgml/plperl.sgml
+++ b/doc/src/sgml/plperl.sgml
@@ -55,7 +55,10 @@
    syntax:
 
 <programlisting>
-CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-types</replaceable>) RETURNS <replaceable>return-type</replaceable> AS $$
+CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-types</replaceable>) 
+    RETURNS <replaceable>return-type</replaceable> 
+    -- function attributes
+    AS $$
     # PL/Perl function body
 $$ LANGUAGE plperl;
 </programlisting>
@@ -347,6 +350,36 @@ SELECT * FROM perl_set();
 </programlisting>
   </para>
 
+  <para>
+   By default, <type>json</type> and <type>jsonb</type> values are passed to
+   PL/Perl functions and procedures as text. For <type>jsonb</type> it is 
+   possible to convert the values into internal Perl representation automatically
+   using the transforms, see <xref linkend="sql-createtransform"/> and <xref linkend="sql-createfunction"/>. 
+   <filename>jsonb_plperl</filename> extension provides such transform for <type>jsonb</type> data type. 
+   To enable the transform, create this extension and then specify 
+<programlisting>
+  TRANSFORM FOR TYPE jsonb
+</programlisting>
+   in the <literal>CREATE FUNCTION</literal> statement.
+  </para>
+
+  <para>
+   By default, boolean values are passed to plperl as text, namely <literal>'t'</literal>
+   for <literal>true</literal> and <literal>'f'</literal> for <literal>false</literal>. 
+   To transform these values into Perl true and false values, use the transform
+   provided by <filename>bool_plperl</filename> extension.
+   To enable the transform, create this extension and then specify 
+<programlisting>
+  TRANSFORM FOR TYPE bool
+</programlisting>
+   in the <literal>CREATE FUNCTION</literal> statement.
+  </para>
+
+  <para>
+   The above mentioned <type>jsonb</type> and <type>bool</type> transforms are applied for function arguments,
+   its return value and results of SPI database queries performed inside the function.
+  </para>
+
   <para>
    If you wish to use the <literal>strict</literal> pragma with your code you
    have a few options. For temporary global use you can <command>SET</command>
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 834c2c39d1..809a2bab0d 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -43,6 +43,7 @@ my $contrib_extrasource = {
 	'seg'  => [ 'contrib/seg/segscan.l',   'contrib/seg/segparse.y' ],
 };
 my @contrib_excludes = (
+	'bool_plperl',
 	'commit_ts',        'hstore_plperl',
 	'hstore_plpython',  'intagg',
 	'jsonb_plperl',     'jsonb_plpython',
@@ -763,6 +764,9 @@ sub mkvcbuild
 		}
 
 		# Add transform modules dependent on plperl
+		my $bool_plperl = AddTransformModule(
+			'bool_plperl',  'contrib/bool_plperl',
+			'plperl',       'src/pl/plperl');
 		my $hstore_plperl = AddTransformModule(
 			'hstore_plperl', 'contrib/hstore_plperl',
 			'plperl',        'src/pl/plperl',
@@ -773,6 +777,7 @@ sub mkvcbuild
 
 		foreach my $f (@perl_embed_ccflags)
 		{
+			$bool_plperl->AddDefine($f);
 			$hstore_plperl->AddDefine($f);
 			$jsonb_plperl->AddDefine($f);
 		}
diff --git a/contrib/bool_plperl/.gitignore b/contrib/bool_plperl/.gitignore
new file mode 100644
index 0000000000..5dcb3ff972
--- /dev/null
+++ b/contrib/bool_plperl/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/contrib/bool_plperl/Makefile b/contrib/bool_plperl/Makefile
new file mode 100644
index 0000000000..e8c174613c
--- /dev/null
+++ b/contrib/bool_plperl/Makefile
@@ -0,0 +1,39 @@
+# contrib/bool_plperl/Makefile
+
+MODULE_big = bool_plperl
+OBJS = bool_plperl.o $(WIN32RES)
+PGFILEDESC = "bool_plperl - bool transform for plperl"
+
+PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plperl
+
+EXTENSION = bool_plperlu bool_plperl
+DATA = bool_plperlu--1.0.sql bool_plperl--1.0.sql
+
+REGRESS = bool_plperl bool_plperlu
+
+SHLIB_LINK += $(filter -lm, $(LIBS))
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/bool_plperl
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
+
+# We must link libperl explicitly
+ifeq ($(PORTNAME), win32)
+# these settings are the same as for plperl
+override CPPFLAGS += -DPLPERL_HAVE_UID_GID -Wno-comment
+# ... see silliness in plperl Makefile ...
+SHLIB_LINK_INTERNAL += $(sort $(wildcard ../../src/pl/plperl/libperl*.a))
+else
+rpathdir = $(perl_archlibexp)/CORE
+SHLIB_LINK += $(perl_embed_ldflags)
+endif
+
+# As with plperl we need to include the perl_includespec directory last.
+override CPPFLAGS := $(CPPFLAGS) $(perl_embed_ccflags) $(perl_includespec)
diff --git a/contrib/bool_plperl/bool_plperl--1.0.sql b/contrib/bool_plperl/bool_plperl--1.0.sql
new file mode 100644
index 0000000000..00dc3b826f
--- /dev/null
+++ b/contrib/bool_plperl/bool_plperl--1.0.sql
@@ -0,0 +1,19 @@
+/* contrib/bool_plperl/bool_plperl--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION bool_plperl" to load this file. \quit
+
+CREATE FUNCTION bool_to_plperl(val internal) RETURNS internal
+LANGUAGE C STRICT IMMUTABLE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION plperl_to_bool(val internal) RETURNS bool
+LANGUAGE C STRICT IMMUTABLE
+AS 'MODULE_PATHNAME';
+
+CREATE TRANSFORM FOR bool LANGUAGE plperl (
+    FROM SQL WITH FUNCTION bool_to_plperl(internal),
+    TO SQL WITH FUNCTION plperl_to_bool(internal)
+);
+
+COMMENT ON TRANSFORM FOR bool LANGUAGE plperl IS 'transform between bool and Perl';
diff --git a/contrib/bool_plperl/bool_plperl.c b/contrib/bool_plperl/bool_plperl.c
new file mode 100644
index 0000000000..6c94f1e02a
--- /dev/null
+++ b/contrib/bool_plperl/bool_plperl.c
@@ -0,0 +1,27 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "plperl.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(bool_to_plperl);
+
+Datum
+bool_to_plperl(PG_FUNCTION_ARGS)
+{
+	dTHX;
+	return PointerGetDatum(
+		PG_GETARG_BOOL(0) ? &PL_sv_yes : &PL_sv_no
+	);
+}
+
+
+PG_FUNCTION_INFO_V1(plperl_to_bool);
+
+Datum
+plperl_to_bool(PG_FUNCTION_ARGS)
+{
+	dTHX;
+	SV *in = (SV *) PG_GETARG_POINTER(0);
+	PG_RETURN_BOOL( SvTRUE(in) );
+}
diff --git a/contrib/bool_plperl/bool_plperl.control b/contrib/bool_plperl/bool_plperl.control
new file mode 100644
index 0000000000..23cdb00d67
--- /dev/null
+++ b/contrib/bool_plperl/bool_plperl.control
@@ -0,0 +1,6 @@
+# jsonb_plperl extension
+comment = 'transform between bool and plperl'
+default_version = '1.0'
+module_pathname = '$libdir/bool_plperl'
+relocatable = true
+requires = 'plperl'
diff --git a/contrib/bool_plperl/bool_plperlu--1.0.sql b/contrib/bool_plperl/bool_plperlu--1.0.sql
new file mode 100644
index 0000000000..9134d33014
--- /dev/null
+++ b/contrib/bool_plperl/bool_plperlu--1.0.sql
@@ -0,0 +1,19 @@
+/* contrib/json_plperl/bool_plperl--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION bool_plperlu" to load this file. \quit
+
+CREATE FUNCTION bool_to_plperlu(val internal) RETURNS internal
+LANGUAGE C STRICT IMMUTABLE
+AS 'MODULE_PATHNAME', 'bool_to_plperl';
+
+CREATE FUNCTION plperlu_to_bool(val internal) RETURNS bool
+LANGUAGE C STRICT IMMUTABLE
+AS 'MODULE_PATHNAME', 'plperl_to_bool';
+
+CREATE TRANSFORM FOR bool LANGUAGE plperlu (
+    FROM SQL WITH FUNCTION bool_to_plperlu(internal),
+    TO SQL WITH FUNCTION plperlu_to_bool(internal)
+);
+
+COMMENT ON TRANSFORM FOR bool LANGUAGE plperlu IS 'transform between bool and Perl';
diff --git a/contrib/bool_plperl/bool_plperlu.control b/contrib/bool_plperl/bool_plperlu.control
new file mode 100644
index 0000000000..c75b8b53ee
--- /dev/null
+++ b/contrib/bool_plperl/bool_plperlu.control
@@ -0,0 +1,6 @@
+# jsonb_plperl extension
+comment = 'transform between bool and plperlu'
+default_version = '1.0'
+module_pathname = '$libdir/bool_plperl'
+relocatable = true
+requires = 'plperlu'
diff --git a/contrib/bool_plperl/expected/bool_plperl.out b/contrib/bool_plperl/expected/bool_plperl.out
new file mode 100644
index 0000000000..475778c3d8
--- /dev/null
+++ b/contrib/bool_plperl/expected/bool_plperl.out
@@ -0,0 +1,110 @@
+CREATE EXTENSION bool_plperl CASCADE;
+NOTICE:  installing required extension "plperl"
+ --- test transforming from perl 
+CREATE FUNCTION perl2int(int) RETURNS bool
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+CREATE FUNCTION perl2text(text) RETURNS bool
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+CREATE FUNCTION perl2undef() RETURNS bool
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+return undef;
+$$;
+SELECT perl2int(1);
+ perl2int 
+----------
+ t
+(1 row)
+
+SELECT perl2int(0);
+ perl2int 
+----------
+ f
+(1 row)
+
+SELECT perl2text('foo');
+ perl2text 
+-----------
+ t
+(1 row)
+
+SELECT perl2text('');
+ perl2text 
+-----------
+ f
+(1 row)
+
+SELECT perl2undef() IS NULL AS p;
+ p 
+---
+ t
+(1 row)
+
+ --- test transforming to perl 
+CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+my ($x, $y, $z) = @_;
+if(defined($z)) {
+die("NULL mistransformed");
+}
+if(!defined($x)) {
+die("TRUE mistransformed to UNDEF");
+}
+if(!defined($y)) {
+die("FALSE mistransformed to UNDEF");
+}
+if(!$x) {
+die("TRUE mistransformed");
+}
+if($y) {
+die("FALSE mistransformed");
+}
+$$;
+SELECT bool2perl (true, false, NULL);
+ bool2perl 
+-----------
+ 
+(1 row)
+
+ --- test selecting bool through SPI
+CREATE FUNCTION spi_test()  RETURNS void
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+my $rv = spi_exec_query('SELECT true t, false f, NULL n')->{rows}->[0];
+if(! defined ($rv->{t})) {
+die("TRUE mistransformed to UNDEF in SPI");
+}
+if(! defined ($rv->{f})) {
+die("FALSE mistransformed to UNDEF in SPI");
+}
+if( defined ($rv->{n})) {
+die("NULL mistransformed in SPI");
+}
+if(! $rv->{t} ) {
+die("TRUE mistransformed in SPI");
+}
+if(  $rv->{f} ) {
+die("FALSE mistransformed in SPI");
+}
+$$;
+SELECT spi_test();
+ spi_test 
+----------
+ 
+(1 row)
+
+\set VERBOSITY terse \\ -- suppress cascade details
+DROP EXTENSION plperl CASCADE;
+NOTICE:  drop cascades to 6 other objects
diff --git a/contrib/bool_plperl/expected/bool_plperlu.out b/contrib/bool_plperl/expected/bool_plperlu.out
new file mode 100644
index 0000000000..679e9ee011
--- /dev/null
+++ b/contrib/bool_plperl/expected/bool_plperlu.out
@@ -0,0 +1,110 @@
+CREATE EXTENSION bool_plperlu CASCADE;
+NOTICE:  installing required extension "plperlu"
+ --- test transforming from perl
+CREATE FUNCTION perl2int(int) RETURNS bool
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+CREATE FUNCTION perl2text(text) RETURNS bool
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+CREATE FUNCTION perl2undef() RETURNS bool
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+return undef;
+$$;
+SELECT perl2int(1);
+ perl2int 
+----------
+ t
+(1 row)
+
+SELECT perl2int(0);
+ perl2int 
+----------
+ f
+(1 row)
+
+SELECT perl2text('foo');
+ perl2text 
+-----------
+ t
+(1 row)
+
+SELECT perl2text('');
+ perl2text 
+-----------
+ f
+(1 row)
+
+SELECT perl2undef() IS NULL AS p;
+ p 
+---
+ t
+(1 row)
+
+ --- test transforming to perl 
+CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+my ($x, $y, $z) = @_;
+if(defined($z)) {
+die("NULL mistransformed");
+}
+if(!defined($x)) {
+die("TRUE mistransformed to UNDEF");
+}
+if(!defined($y)) {
+die("FALSE mistransformed to UNDEF");
+}
+if(!$x) {
+die("TRUE mistransformed");
+}
+if($y) {
+die("FALSE mistransformed");
+}
+$$;
+SELECT bool2perl (true, false, NULL);
+ bool2perl 
+-----------
+ 
+(1 row)
+
+ --- test selecting bool through SPI
+CREATE FUNCTION spi_test()  RETURNS void
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+my $rv = spi_exec_query('SELECT true t, false f, NULL n')->{rows}->[0];
+if(! defined ($rv->{t})) {
+die("TRUE mistransformed to UNDEF in SPI");
+}
+if(! defined ($rv->{f})) {
+die("FALSE mistransformed to UNDEF in SPI");
+}
+if( defined ($rv->{n})) {
+die("NULL mistransformed in SPI");
+}
+if(! $rv->{t} ) {
+die("TRUE mistransformed in SPI");
+}
+if(  $rv->{f} ) {
+die("FALSE mistransformed in SPI");
+}
+$$;
+SELECT spi_test();
+ spi_test 
+----------
+ 
+(1 row)
+
+\set VERBOSITY terse \\ -- suppress cascade details
+DROP EXTENSION plperlu CASCADE;
+NOTICE:  drop cascades to 6 other objects
diff --git a/contrib/bool_plperl/sql/bool_plperl.sql b/contrib/bool_plperl/sql/bool_plperl.sql
new file mode 100644
index 0000000000..8d1e4a6c2c
--- /dev/null
+++ b/contrib/bool_plperl/sql/bool_plperl.sql
@@ -0,0 +1,83 @@
+CREATE EXTENSION bool_plperl CASCADE;
+
+ --- test transforming from perl 
+CREATE FUNCTION perl2int(int) RETURNS bool
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+
+CREATE FUNCTION perl2text(text) RETURNS bool
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+
+CREATE FUNCTION perl2undef() RETURNS bool
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+return undef;
+$$;
+
+SELECT perl2int(1);
+SELECT perl2int(0);
+SELECT perl2text('foo');
+SELECT perl2text('');
+SELECT perl2undef() IS NULL AS p;
+
+ --- test transforming to perl 
+CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+my ($x, $y, $z) = @_;
+if(defined($z)) {
+die("NULL mistransformed");
+}
+if(!defined($x)) {
+die("TRUE mistransformed to UNDEF");
+}
+if(!defined($y)) {
+die("FALSE mistransformed to UNDEF");
+}
+if(!$x) {
+die("TRUE mistransformed");
+}
+if($y) {
+die("FALSE mistransformed");
+}
+$$;
+
+SELECT bool2perl (true, false, NULL);
+
+ --- test selecting bool through SPI
+
+CREATE FUNCTION spi_test()  RETURNS void
+LANGUAGE plperl
+TRANSFORM FOR TYPE bool
+AS $$
+my $rv = spi_exec_query('SELECT true t, false f, NULL n')->{rows}->[0];
+if(! defined ($rv->{t})) {
+die("TRUE mistransformed to UNDEF in SPI");
+}
+if(! defined ($rv->{f})) {
+die("FALSE mistransformed to UNDEF in SPI");
+}
+if( defined ($rv->{n})) {
+die("NULL mistransformed in SPI");
+}
+if(! $rv->{t} ) {
+die("TRUE mistransformed in SPI");
+}
+if(  $rv->{f} ) {
+die("FALSE mistransformed in SPI");
+}
+$$;
+
+SELECT spi_test();
+
+\set VERBOSITY terse \\ -- suppress cascade details
+DROP EXTENSION plperl CASCADE;
diff --git a/contrib/bool_plperl/sql/bool_plperlu.sql b/contrib/bool_plperl/sql/bool_plperlu.sql
new file mode 100644
index 0000000000..f7ce247988
--- /dev/null
+++ b/contrib/bool_plperl/sql/bool_plperlu.sql
@@ -0,0 +1,83 @@
+CREATE EXTENSION bool_plperlu CASCADE;
+
+ --- test transforming from perl
+CREATE FUNCTION perl2int(int) RETURNS bool
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+
+CREATE FUNCTION perl2text(text) RETURNS bool
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+return shift;
+$$;
+
+CREATE FUNCTION perl2undef() RETURNS bool
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+return undef;
+$$;
+
+SELECT perl2int(1);
+SELECT perl2int(0);
+SELECT perl2text('foo');
+SELECT perl2text('');
+SELECT perl2undef() IS NULL AS p;
+
+ --- test transforming to perl 
+CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+my ($x, $y, $z) = @_;
+if(defined($z)) {
+die("NULL mistransformed");
+}
+if(!defined($x)) {
+die("TRUE mistransformed to UNDEF");
+}
+if(!defined($y)) {
+die("FALSE mistransformed to UNDEF");
+}
+if(!$x) {
+die("TRUE mistransformed");
+}
+if($y) {
+die("FALSE mistransformed");
+}
+$$;
+
+SELECT bool2perl (true, false, NULL);
+
+ --- test selecting bool through SPI
+
+CREATE FUNCTION spi_test()  RETURNS void
+LANGUAGE plperlu
+TRANSFORM FOR TYPE bool
+AS $$
+my $rv = spi_exec_query('SELECT true t, false f, NULL n')->{rows}->[0];
+if(! defined ($rv->{t})) {
+die("TRUE mistransformed to UNDEF in SPI");
+}
+if(! defined ($rv->{f})) {
+die("FALSE mistransformed to UNDEF in SPI");
+}
+if( defined ($rv->{n})) {
+die("NULL mistransformed in SPI");
+}
+if(! $rv->{t} ) {
+die("TRUE mistransformed in SPI");
+}
+if(  $rv->{f} ) {
+die("FALSE mistransformed in SPI");
+}
+$$;
+
+SELECT spi_test();
+
+\set VERBOSITY terse \\ -- suppress cascade details
+DROP EXTENSION plperlu CASCADE;
