From 563b2e7b6564c9444afe4e06f6f99c36a3e8403d Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Mon, 19 Mar 2018 19:43:44 +0900
Subject: [PATCH 2/2] test module.

---
 src/test/modules/Makefile                          |    1 +
 src/test/modules/test_subscription/Makefile        |   18 +++++
 src/test/modules/test_subscription/TAGS            |    1 +
 .../modules/test_subscription/testsub1--1.0.sql    |   22 ++++++
 src/test/modules/test_subscription/testsub1.c      |   42 ++++++++++++
 .../modules/test_subscription/testsub1.control     |    4 +
 .../modules/test_subscription/testsub2--1.0.sql    |   22 ++++++
 src/test/modules/test_subscription/testsub2.c      |   45 ++++++++++++
 .../modules/test_subscription/testsub2.control     |    4 +
 src/test/subscription/Makefile                     |    2 +-
 src/test/subscription/t/010_typemap.pl             |   71 ++++++++++++++++++++
 11 files changed, 231 insertions(+), 1 deletions(-)
 create mode 100644 src/test/modules/test_subscription/Makefile
 create mode 120000 src/test/modules/test_subscription/TAGS
 create mode 100644 src/test/modules/test_subscription/testsub1--1.0.sql
 create mode 100644 src/test/modules/test_subscription/testsub1.c
 create mode 100644 src/test/modules/test_subscription/testsub1.control
 create mode 100644 src/test/modules/test_subscription/testsub2--1.0.sql
 create mode 100644 src/test/modules/test_subscription/testsub2.c
 create mode 100644 src/test/modules/test_subscription/testsub2.control
 create mode 100644 src/test/subscription/t/010_typemap.pl

diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 7294b69..a455634 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -17,6 +17,7 @@ SUBDIRS = \
 		  test_rbtree \
 		  test_rls_hooks \
 		  test_shm_mq \
+		  test_subscription \
 		  worker_spi
 
 all: submake-generated-headers
diff --git a/src/test/modules/test_subscription/Makefile b/src/test/modules/test_subscription/Makefile
new file mode 100644
index 0000000..12993e0
--- /dev/null
+++ b/src/test/modules/test_subscription/Makefile
@@ -0,0 +1,18 @@
+# src/test/modules/test_subscription/Makefile
+
+MODULES = testsub1 testsub2
+EXTENSION = testsub1 testsub2
+DATA = testsub1--1.0.sql testsub2--1.0.sql
+
+PGFILEDESC = "test_subscription - mock extensions for subscription test"
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_subscription
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_subscription/TAGS b/src/test/modules/test_subscription/TAGS
new file mode 120000
index 0000000..1a96393
--- /dev/null
+++ b/src/test/modules/test_subscription/TAGS
@@ -0,0 +1 @@
+/home/masahiko/source/postgresql/TAGS
\ No newline at end of file
diff --git a/src/test/modules/test_subscription/testsub1--1.0.sql b/src/test/modules/test_subscription/testsub1--1.0.sql
new file mode 100644
index 0000000..43ab718
--- /dev/null
+++ b/src/test/modules/test_subscription/testsub1--1.0.sql
@@ -0,0 +1,22 @@
+/* src/test/modules/test_subscription/testsub1--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION testsub1" to load this file. \quit
+
+CREATE TYPE dummytext;
+
+CREATE FUNCTION dummytext_in(cstring)
+RETURNS dummytext
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION dummytext_out(dummytext)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE TYPE dummytext (
+       INTERNALLENGTH = -1,
+       INPUT = dummytext_in,
+       OUTPUT = dummytext_out
+);
diff --git a/src/test/modules/test_subscription/testsub1.c b/src/test/modules/test_subscription/testsub1.c
new file mode 100644
index 0000000..e94fbe7
--- /dev/null
+++ b/src/test/modules/test_subscription/testsub1.c
@@ -0,0 +1,42 @@
+/*--------------------------------------------------------------------------
+ *
+ * testsub1.c
+ *		Code for testing logical replication subscriptions.
+ *
+ * Copyright (c) 2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		src/test/modules/test_subscription/testsub1.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "utils/builtins.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(dummytext_in);
+PG_FUNCTION_INFO_V1(dummytext_out);
+
+/* Dummy input of data type function */
+Datum
+dummytext_in(PG_FUNCTION_ARGS)
+{
+	char	*inputText = PG_GETARG_CSTRING(0);
+
+	if (inputText)
+		elog(LOG, "input text: \"%s\"", inputText);
+
+	PG_RETURN_TEXT_P(cstring_to_text(inputText));
+}
+
+/* Dummy output of data type function */
+Datum
+dummytext_out(PG_FUNCTION_ARGS)
+{
+	Datum	txt = PG_GETARG_DATUM(0);
+
+	PG_RETURN_CSTRING(TextDatumGetCString(txt));
+}
diff --git a/src/test/modules/test_subscription/testsub1.control b/src/test/modules/test_subscription/testsub1.control
new file mode 100644
index 0000000..746bba3
--- /dev/null
+++ b/src/test/modules/test_subscription/testsub1.control
@@ -0,0 +1,4 @@
+comment = 'extension testsub1 to test subscriptions'
+default_version = '1.0'
+module_pathname = '$libdir/testsub1'
+relocatable = true
diff --git a/src/test/modules/test_subscription/testsub2--1.0.sql b/src/test/modules/test_subscription/testsub2--1.0.sql
new file mode 100644
index 0000000..4c94dd3
--- /dev/null
+++ b/src/test/modules/test_subscription/testsub2--1.0.sql
@@ -0,0 +1,22 @@
+/* src/test/modules/test_subscription/testsub2--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION testsub2" to load this file. \quit
+
+CREATE TYPE dummyint;
+
+CREATE FUNCTION dummyint_in(cstring)
+RETURNS dummyint
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION dummyint_out(dummyint)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE TYPE dummyint (
+	   LIKE = pg_catalog.int4,
+       INPUT = dummyint_in,
+       OUTPUT = dummyint_out
+);
diff --git a/src/test/modules/test_subscription/testsub2.c b/src/test/modules/test_subscription/testsub2.c
new file mode 100644
index 0000000..d1a91b6
--- /dev/null
+++ b/src/test/modules/test_subscription/testsub2.c
@@ -0,0 +1,45 @@
+/*--------------------------------------------------------------------------
+ *
+ * testsub2.c
+ *		Code for testing logical replication subscriptions.
+ *
+ * Copyright (c) 2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		src/test/modules/test_subscription/testsub2.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "utils/builtins.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(dummyint_in);
+PG_FUNCTION_INFO_V1(dummyint_out);
+
+/* Dummy input of data type function */
+Datum
+dummyint_in(PG_FUNCTION_ARGS)
+{
+	char   *num = PG_GETARG_CSTRING(0);
+	int32	val;
+
+	val = pg_atoi(num, sizeof(int32), '\0');
+	elog(LOG, "input int: %d", val);
+
+	PG_RETURN_INT32(val);
+}
+
+/* Dummy output of data type function */
+Datum
+dummyint_out(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	char	   *result = (char *) palloc(12);	/* sign, 10 digits, '\0' */
+
+	pg_ltoa(arg1, result);
+	PG_RETURN_CSTRING(result);
+}
diff --git a/src/test/modules/test_subscription/testsub2.control b/src/test/modules/test_subscription/testsub2.control
new file mode 100644
index 0000000..8a0341c
--- /dev/null
+++ b/src/test/modules/test_subscription/testsub2.control
@@ -0,0 +1,4 @@
+comment = 'extension testsub2 to test subscriptions'
+default_version = '1.0'
+module_pathname = '$libdir/testsub2'
+relocatable = true
diff --git a/src/test/subscription/Makefile b/src/test/subscription/Makefile
index 0f3d209..f5e76bb 100644
--- a/src/test/subscription/Makefile
+++ b/src/test/subscription/Makefile
@@ -13,7 +13,7 @@ subdir = src/test/subscription
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-EXTRA_INSTALL = contrib/hstore
+EXTRA_INSTALL = contrib/hstore src/test/modules/test_subscription
 
 check:
 	$(prove_check)
diff --git a/src/test/subscription/t/010_typemap.pl b/src/test/subscription/t/010_typemap.pl
new file mode 100644
index 0000000..f893622
--- /dev/null
+++ b/src/test/subscription/t/010_typemap.pl
@@ -0,0 +1,71 @@
+# This tests that the errors when data type conversion are correctly
+# handled by logical replication apply workers
+use strict;
+use warnings;
+
+use PostgresNode;
+use TestLib;
+use Test::More tests => 3;
+
+# Initialize publisher node
+my $node_publisher = get_new_node('publisher');
+$node_publisher->init(allows_streaming => 'logical');
+$node_publisher->start;
+
+# Create subscriber node
+my $node_subscriber = get_new_node('subscriber');
+$node_subscriber->init(allows_streaming => 'logical');
+$node_subscriber->start;
+
+# Setup same table by different steps so that publisher and subscriber get
+# different datatype OIDs.
+$node_publisher->safe_psql('postgres', qq[
+CREATE EXTENSION testsub2;
+CREATE EXTENSION testsub1;
+CREATE TABLE test (a dummytext, b dummyint);]);
+
+$node_subscriber->safe_psql('postgres', qq[
+CREATE EXTENSION testsub1;
+CREATE EXTENSION testsub2;
+CREATE TABLE test (b dummyint, a dummytext);]);
+
+# Setup logical replication
+my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
+$node_publisher->safe_psql('postgres', qq[
+CREATE PUBLICATION tap_pub FOR TABLE test
+]);
+my $appname = 'tap_sub';
+$node_subscriber->safe_psql('postgres', qq[
+CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (slot_name = tap_sub_slot, copy_data = false)
+]);
+
+# Truncate the logfile on subscriber before insertion in
+# order to capture logs emitted by the callback function
+# for the datatype conversion.
+truncate $node_subscriber->logfile, 0;
+
+# Insert test data, which will lead to call the callback function for the data
+# type conversion on subscriber.
+$node_publisher->safe_psql('postgres', qq(
+INSERT INTO test VALUES ('one', '1');
+));
+
+$node_publisher->wait_for_catchup($appname);
+
+# Check the callback function behavior for datatype conversion
+# by checking the logs.
+my $log = TestLib::slurp_file($node_subscriber->logfile);
+like ($log,
+	  qr/processing remote data for replication target relation "public.test" column "a", remote type public.dummytext, local type public.dummytext/,
+	  'callbackfunction of datatype conversion1');
+like ($log,
+	  qr/processing remote data for replication target relation "public.test" column "b", remote type public.dummyint, local type public.dummyint/,
+	  'callbackfunction of datatype conversion1');
+
+# Check the data on subscriber
+my $result = $node_subscriber->safe_psql('postgres', qq(
+SELECT a FROM test;
+));
+
+# Inserted data is replicated correctly
+is( $result, 'one');
-- 
1.7.1

