Hmm, things are bit different.

At Thu, 23 Mar 2017 12:13:07 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI 
<horiguchi.kyot...@lab.ntt.co.jp> wrote in 
<20170323.121307.241436413.horiguchi.kyot...@lab.ntt.co.jp>
> > Ok, I'll write a small script to generate a set of "conversion
> > dump" and try to write README.sanity_check describing how to use
> > it.
> 
> I found that there's no way to identify the character domain of a
> conversion on SQL interface. Unconditionally giving from 0 to
> 0xffffffff as a bytea string yields too-bloat result by containg
> many bogus lines.  (If \x40 is a character, convert() also
> accepts \x4040, \x404040 and \x40404040)
> 
> One more annoyance is the fact that mappings and conversion
> procedures are not in one-to-one correspondence. The
> corresnponcence is hidden in conversion_procs/*.c files so we
> should extract it from them or provide as knowledge. Both don't
> seem good.
> 
> Finally, it seems that I have no choice than resurrecting
> map_checker. The exactly the same one no longer works but
> map_dumper.c with almost the same structure will work.
> 
> If no one objects to adding map_dumper.c and
> gen_mapdumper_header.pl (tentavie name, of course), I'll make a
> patch to do that.

The scirpt or executable should be compatible between versions
but pg_mb_radix_conv is not. On the other hand more upper level
API reuiqres server stuff.

Finally I made an extension that dumps encoding conversion.

encoding_dumper('SJIS', 'UTF-8') or encoding_dumper(35, 6)

Then it returns the following output consists of two BYTEAs.

 srccode | dstcode  
---------+----------
 \x01    | \x01
 \x02    | \x02
...
 \xfc4a  | \xe9b899
 \xfc4b  | \xe9bb91
(7914 rows)

This returns in a very short time but doesn't when srccode
extends to 4 bytes. As an extreme example the following,

> =# select * from encoding_dumper('UTF-8', 'LATIN1');

takes over 2 minutes to return only 255 rows. We cannot determine
the exact domain without looking into map data so the function
cannot do other than looping through all the four-byte values.
Providing a function that gives the domain for a conversion was a
mess, especially for artithmetic-conversions. The following query
took 94 minutes to give 25M lines/125MB.  In short, that's a
crap. (the first attached)

SELECT x.conname, y.srccode, y.dstcode
FROM
 (
    SELECT conname, conforencoding, contoencoding
    FROM pg_conversion c
    WHERE pg_char_to_encoding('UTF-8') IN (c.conforencoding, c.contoencoding)
      AND pg_char_to_encoding('SQL_ASCII')
          NOT IN (c.conforencoding, c.contoencoding)) as x,
 LATERAL (
   SELECT srccode, dstcode
   FROM  encoding_dumper(x.conforencoding, x.contoencoding)) as y
ORDER BY x.conforencoding, x.contoencoding, y.srccode;


As the another way, I added a measure to generate plain mapping
lists corresponding to .map files (similar to old maps but
simpler) and this finishes the work within a second.

$ make mapdumps

If we will not shortly change the framework of mapped character
conversion, the dumper program may be useful but I'm not sure
this is reasonable as sanity check for future modifications.  In
the PoC, pg_mb_radix_tree() is copied into map_checker.c but this
needs to be a separate file again.  (the second attached)


regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 3763d91d99521f0cfc305bd2199fcb5a263d758d Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Mon, 27 Mar 2017 09:46:04 +0900
Subject: [PATCH 1/2] encoding_dumper

---
 contrib/encoding_dumper/Makefile                 |  17 +++
 contrib/encoding_dumper/encoding_dumper--0.1.sql |  23 ++++
 contrib/encoding_dumper/encoding_dumper.c        | 167 +++++++++++++++++++++++
 contrib/encoding_dumper/encoding_dumper.control  |   5 +
 4 files changed, 212 insertions(+)
 create mode 100755 contrib/encoding_dumper/Makefile
 create mode 100755 contrib/encoding_dumper/encoding_dumper--0.1.sql
 create mode 100755 contrib/encoding_dumper/encoding_dumper.c
 create mode 100755 contrib/encoding_dumper/encoding_dumper.control

diff --git a/contrib/encoding_dumper/Makefile b/contrib/encoding_dumper/Makefile
new file mode 100755
index 0000000..54e9cfc
--- /dev/null
+++ b/contrib/encoding_dumper/Makefile
@@ -0,0 +1,17 @@
+# src/backend/util/mb/Unicode/encoding_dumper/Makefile
+
+MODULES = encoding_dumper
+EXTENSION = encoding_dumper
+DATA = encoding_dumper--0.1.sql
+PGFILEDESC = "encoding_dumper - return encoding dump"
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/encoding_dumper
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/encoding_dumper/encoding_dumper--0.1.sql b/contrib/encoding_dumper/encoding_dumper--0.1.sql
new file mode 100755
index 0000000..4f67946
--- /dev/null
+++ b/contrib/encoding_dumper/encoding_dumper--0.1.sql
@@ -0,0 +1,23 @@
+/* .sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_stat_statements" to load this file. \quit
+
+CREATE FUNCTION encoding_dumper(IN srcenc int,
+	   IN	dstenc int,
+	   OUT 	srccode bytea,
+	   OUT 	dstcode bytea
+)
+RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'encoding_dumper'
+LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
+
+CREATE FUNCTION encoding_dumper(IN srcencname text,
+	   IN	dstencname text,
+	   OUT	srccode bytea,
+	   OUT	dstcode bytea
+)
+RETURNS SETOF record AS '
+SELECT * FROM encoding_dumper(pg_char_to_encoding(srcencname),
+							  pg_char_to_encoding(dstencname));
+' LANGUAGE SQL;
diff --git a/contrib/encoding_dumper/encoding_dumper.c b/contrib/encoding_dumper/encoding_dumper.c
new file mode 100755
index 0000000..ad30c16
--- /dev/null
+++ b/contrib/encoding_dumper/encoding_dumper.c
@@ -0,0 +1,167 @@
+/*-------------------------------------------------------------------------
+ *
+ *	  Radix map checker
+ *
+ * Copyright (c) 2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/mb/Unicode/map_checker.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+#include "catalog/namespace.h"
+#include "funcapi.h"
+#include "mb/pg_wchar.h"
+#include "miscadmin.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(encoding_dumper);
+
+static int set_byteastr(unsigned char *buf, unsigned long val);
+
+static int
+set_byteastr(unsigned char *buf, unsigned long val)
+{
+	unsigned char *p = buf;
+
+	if (val > 0xffffffff)
+	{
+		fprintf(stderr, "Code out of range : %ld\n", val);
+		exit(1);
+	}
+	if (val > 0xffffff)
+		*p++ = (val >> 24) & 0xff;
+	if (val > 0xffff)
+		*p++ = (val >> 16) & 0xff;
+	if (val > 0xff)
+		*p++ = (val >> 8) & 0xff;
+	*p++ = val & 0xff;
+
+	return p - buf;
+}
+
+Datum
+encoding_dumper(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+	int	src_encoding = PG_GETARG_INT32(0);
+	int	dst_encoding = PG_GETARG_INT32(1);
+	MemoryContext per_query_ctx;
+	MemoryContext oldcontext;
+	TupleDesc	tupdesc;
+	Tuplestorestate *tupstore;
+	unsigned long i, max;
+	Oid proc;
+
+	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("set-valued function called in context that cannot accept a set")));
+	if (!(rsinfo->allowedModes & SFRM_Materialize))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("materialize mode required, but it is not " \
+						"allowed in this context")));
+
+	/* Switch into long-lived context to construct returned data structures */
+	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+	oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	if (tupdesc->natts != 2)
+		elog(ERROR, "incorrect number of output arguments: %d", tupdesc->natts);
+
+	tupstore = tuplestore_begin_heap(true, false, work_mem);
+	rsinfo->returnMode = SFRM_Materialize;
+	rsinfo->setResult = tupstore;
+	rsinfo->setDesc = tupdesc;
+
+	MemoryContextSwitchTo(oldcontext);
+
+	if (src_encoding < 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid source encoding: %d", src_encoding)));
+	if (dst_encoding < 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid destination encoding: %d", dst_encoding)));
+
+	proc = FindDefaultConversionProc(src_encoding, dst_encoding);
+	if (!OidIsValid(proc))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_FUNCTION),
+				 errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
+						pg_encoding_to_char(src_encoding),
+						pg_encoding_to_char(dst_encoding))));
+
+	/* We don't bother checking beyond the domain */
+	max = 0x1L << (pg_encoding_max_length(src_encoding) * 8);
+
+	for (i = 0 ; i < max ; i++)
+	{
+		unsigned char src[16];
+		unsigned char dst[16];
+		Datum		values[2];
+		bool		nulls[2];
+		bytea	*srcval;
+		bytea	*dstval;
+		int srclen, dstlen, l;
+		bool	failed = false;
+
+		/* The interval here is quite arbitrary */
+		if ((i & 0xffffff) == 0)
+			CHECK_FOR_INTERRUPTS();
+
+		srclen = set_byteastr(src, i);
+		l = pg_verify_mbstr_len(src_encoding, (const char *)src, srclen, true);
+		if (l != 1)
+			continue;
+
+		PG_TRY();
+		{
+			OidFunctionCall5(proc,
+							 Int32GetDatum(src_encoding),
+							 Int32GetDatum(dst_encoding),
+							 CStringGetDatum(src),
+							 CStringGetDatum(dst),
+							 Int32GetDatum(srclen));
+		}
+		PG_CATCH();
+		{
+			FlushErrorState();
+			failed = true;
+		}
+		PG_END_TRY();
+
+		if (failed)
+			continue;
+
+		dstlen = strlen((const char *)dst);
+
+		srcval = (bytea *) MemoryContextAlloc(per_query_ctx, srclen + VARHDRSZ);
+		SET_VARSIZE(srcval, srclen + VARHDRSZ);
+		memcpy(VARDATA(srcval), src, srclen);
+
+		dstval = (bytea *) MemoryContextAlloc(per_query_ctx, dstlen + VARHDRSZ);
+		SET_VARSIZE(dstval, dstlen + VARHDRSZ);
+		memcpy(VARDATA(dstval), dst, dstlen);
+
+		memset(nulls, 0, sizeof(nulls));
+
+		values[0] = PointerGetDatum(srcval);
+		values[1] = PointerGetDatum(dstval);
+
+		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+	}
+
+	tuplestore_donestoring(tupstore);
+
+	return (Datum) 0;
+}
diff --git a/contrib/encoding_dumper/encoding_dumper.control b/contrib/encoding_dumper/encoding_dumper.control
new file mode 100755
index 0000000..459dd54
--- /dev/null
+++ b/contrib/encoding_dumper/encoding_dumper.control
@@ -0,0 +1,5 @@
+# encoding dumper extension
+comment = 'dump encodings'
+default_version = '0.1'
+module_pathname = '$libdir/encoding_dumper'
+relocatable = true
-- 
2.9.2

>From 2cbabca59cf16e0166a9224f0c15607618265899 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Mon, 27 Mar 2017 18:35:24 +0900
Subject: [PATCH 2/2] map_dumper

---
 src/backend/utils/mb/Unicode/Makefile           |  14 ++
 src/backend/utils/mb/Unicode/make_map_dumper.pl |  56 ++++++
 src/backend/utils/mb/Unicode/map_dumper.c       | 236 ++++++++++++++++++++++++
 3 files changed, 306 insertions(+)
 create mode 100644 src/backend/utils/mb/Unicode/make_map_dumper.pl
 create mode 100644 src/backend/utils/mb/Unicode/map_dumper.c

diff --git a/src/backend/utils/mb/Unicode/Makefile b/src/backend/utils/mb/Unicode/Makefile
index 8f3afa0..fa70caf 100644
--- a/src/backend/utils/mb/Unicode/Makefile
+++ b/src/backend/utils/mb/Unicode/Makefile
@@ -70,6 +70,8 @@ WINTEXTS = CP866.TXT CP874.TXT CP936.TXT \
 GENERICTEXTS = $(ISO8859TEXTS) $(WINTEXTS) \
 	KOI8-R.TXT KOI8-U.TXT
 
+OBJS = map_dumper.o
+
 all: $(MAPS)
 
 $(GENERICMAPS): UCS_to_most.pl $(GENERICTEXTS)
@@ -108,6 +110,12 @@ euc_jis_2004_to_utf8.map utf8_to_euc_jis_2004.map: UCS_to_EUC_JIS_2004.pl euc-ji
 shift_jis_2004_to_utf8.map utf8_to_shift_jis_2004.map: UCS_to_SHIFT_JIS_2004.pl sjis-0213-2004-std.txt
 	$(PERL) $<
 
+mapdumps: map_dumper
+	./map_dumper
+
+clean:
+	rm -f *.dump $(OBJS) map_dumper.h
+
 distclean: clean
 	rm -f $(TEXTS)
 
@@ -147,3 +155,9 @@ $(filter-out CP8%,$(WINTEXTS)) CP932.TXT CP950.TXT:
 
 $(filter CP8%,$(WINTEXTS)):
 	$(DOWNLOAD) http://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/$(@F)
+
+map_dumper: map_dumper.c map_dumper.h
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LDFLAGS_EX) map_dumper.c -o $@
+
+map_dumper.h: make_map_dumper.pl
+	$(PERL) make_map_dumper.pl
diff --git a/src/backend/utils/mb/Unicode/make_map_dumper.pl b/src/backend/utils/mb/Unicode/make_map_dumper.pl
new file mode 100644
index 0000000..c338a68
--- /dev/null
+++ b/src/backend/utils/mb/Unicode/make_map_dumper.pl
@@ -0,0 +1,56 @@
+#! /usr/bin/perl
+use strict;
+
+# collect all radix mapfiles
+opendir(my $dh, ".") || die "failed to open directory: .";
+my @maps = grep { /\.map$/ } readdir($dh);
+closedir($dh);
+
+# generate sanity checker source
+my $out;
+open($out, '>', "map_dumper.h")
+  || die "cannot open file to write: map_dumper.h";
+
+# add #include lines for all radix maps and corresponding plain maps
+foreach my $i (sort @maps)
+{
+	print $out "#include \"$i\"\n";
+}
+
+print $out <<'EOF';
+
+struct mappair
+{
+	const char			   *name;
+	const pg_mb_radix_tree *rt;
+} mappairs[] = {
+EOF
+
+# generate variable names for the array of mappair
+my @mapnames = map { my $m = $_; $m =~ s/\.map//; $m } @maps;
+
+# write the content of mappairs array.
+foreach my $m (@mapnames)
+{
+	if ($m =~ /^utf8_to_(.*)$/)
+	{
+		my $e = uc($1);
+		print $out
+		"	{\"$m\", &$1_from_unicode_tree}";
+	}
+	elsif ($m =~ /^(.*)_to_utf8$/)
+	{
+		my $e = uc($1);
+		print $out
+		  "	{\"$m\", &$1_to_unicode_tree}";
+	}
+	else
+	{
+		die "Unrecognizable map name: $m";
+	}
+	print $out ",\n";
+}
+
+print $out "	{NULL, NULL}\n};\n";
+
+close($out);
diff --git a/src/backend/utils/mb/Unicode/map_dumper.c b/src/backend/utils/mb/Unicode/map_dumper.c
new file mode 100644
index 0000000..c693e15
--- /dev/null
+++ b/src/backend/utils/mb/Unicode/map_dumper.c
@@ -0,0 +1,236 @@
+/*-------------------------------------------------------------------------
+ *
+ *	  Radix map dumper
+ *
+ * Copyright (c) 2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/mb/Unicode/map_dumper.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+#include "mb/pg_wchar.h"
+
+#include "map_dumper.h"
+
+void dump_radix_tree(FILE *out, const pg_mb_radix_tree *rt);
+
+static inline uint32
+pg_mb_radix_conv(const pg_mb_radix_tree *rt,
+				 int l,
+				 unsigned char b1,
+				 unsigned char b2,
+				 unsigned char b3,
+				 unsigned char b4)
+{
+	if (l == 4)
+	{
+		/* 4-byte code */
+
+		/* check code validity */
+		if (b1 < rt->b4_1_lower || b1 > rt->b4_1_upper ||
+			b2 < rt->b4_2_lower || b2 > rt->b4_2_upper ||
+			b3 < rt->b4_3_lower || b3 > rt->b4_3_upper ||
+			b4 < rt->b4_4_lower || b4 > rt->b4_4_upper)
+			return 0;
+
+		/* perform lookup */
+		if (rt->chars32)
+		{
+			uint32		idx = rt->b4root;
+
+			idx = rt->chars32[b1 + idx - rt->b4_1_lower];
+			idx = rt->chars32[b2 + idx - rt->b4_2_lower];
+			idx = rt->chars32[b3 + idx - rt->b4_3_lower];
+			return rt->chars32[b4 + idx - rt->b4_4_lower];
+		}
+		else
+		{
+			uint16		idx = rt->b4root;
+
+			idx = rt->chars16[b1 + idx - rt->b4_1_lower];
+			idx = rt->chars16[b2 + idx - rt->b4_2_lower];
+			idx = rt->chars16[b3 + idx - rt->b4_3_lower];
+			return rt->chars16[b4 + idx - rt->b4_4_lower];
+		}
+	}
+	else if (l == 3)
+	{
+		/* 3-byte code */
+
+		/* check code validity */
+		if (b2 < rt->b3_1_lower || b2 > rt->b3_1_upper ||
+			b3 < rt->b3_2_lower || b3 > rt->b3_2_upper ||
+			b4 < rt->b3_3_lower || b4 > rt->b3_3_upper)
+			return 0;
+
+		/* perform lookup */
+		if (rt->chars32)
+		{
+			uint32		idx = rt->b3root;
+
+			idx = rt->chars32[b2 + idx - rt->b3_1_lower];
+			idx = rt->chars32[b3 + idx - rt->b3_2_lower];
+			return rt->chars32[b4 + idx - rt->b3_3_lower];
+		}
+		else
+		{
+			uint16		idx = rt->b3root;
+
+			idx = rt->chars16[b2 + idx - rt->b3_1_lower];
+			idx = rt->chars16[b3 + idx - rt->b3_2_lower];
+			return rt->chars16[b4 + idx - rt->b3_3_lower];
+		}
+	}
+	else if (l == 2)
+	{
+		/* 2-byte code */
+
+		/* check code validity - first byte */
+		if (b3 < rt->b2_1_lower || b3 > rt->b2_1_upper ||
+			b4 < rt->b2_2_lower || b4 > rt->b2_2_upper)
+			return 0;
+
+		/* perform lookup */
+		if (rt->chars32)
+		{
+			uint32		idx = rt->b2root;
+
+			idx = rt->chars32[b3 + idx - rt->b2_1_lower];
+			return rt->chars32[b4 + idx - rt->b2_2_lower];
+		}
+		else
+		{
+			uint16		idx = rt->b2root;
+
+			idx = rt->chars16[b3 + idx - rt->b2_1_lower];
+			return rt->chars16[b4 + idx - rt->b2_2_lower];
+		}
+	}
+	else if (l == 1)
+	{
+		/* 1-byte code */
+
+		/* check code validity - first byte */
+		if (b4 < rt->b1_lower || b4 > rt->b1_upper)
+			return 0;
+
+		/* perform lookup */
+		if (rt->chars32)
+			return rt->chars32[b4 + rt->b1root - rt->b1_lower];
+		else
+			return rt->chars16[b4 + rt->b1root - rt->b1_lower];
+	}
+	return 0; /* shouldn't happen */
+}
+
+
+static inline void
+print_one_line(FILE *out, uint32 f, uint32 t)
+{
+	fprintf(out, "%x %x\n", f, t);
+}
+
+/*
+ *  pg_mb_radix_tree: dump the whole radix tree conversion
+ */
+void
+dump_radix_tree(FILE *out, const pg_mb_radix_tree *rt)
+{
+	unsigned int b1, b2, b3, b4;
+
+	if (rt->b1_lower > 0 || rt->b1_upper > 0)
+	{
+		for (b4 = rt->b1_lower ; b4 <= rt->b1_upper; b4++)
+		{
+			uint32 r = pg_mb_radix_conv(rt, 1, 0, 0, 0, b4);
+			if (r != 0)
+				print_one_line(out, b4, r);
+		}
+	}
+
+	if (rt->b2_1_lower > 0 || rt->b2_1_upper > 0 ||
+		rt->b2_2_lower > 0 || rt->b2_2_upper > 0)
+	{
+		for (b3 = rt->b2_1_lower ; b3 <= rt->b2_1_upper ; b3++)
+		{
+			for (b4 = rt->b2_2_lower ; b4 <= rt->b2_2_upper ; b4++)
+			{
+				uint32 r = pg_mb_radix_conv(rt, 2, 0, 0, b3, b4);
+				if (r != 0)
+					print_one_line(out, (((uint32)b3) << 8) | b4, r);
+			}
+		}
+	}
+	if (rt->b3_1_lower > 0 || rt->b3_1_upper > 0 ||
+		rt->b3_2_lower > 0 || rt->b3_2_upper > 0 ||
+		rt->b3_3_lower > 0 || rt->b3_3_upper > 0)
+	{
+		for (b2 = rt->b3_1_lower ; b2 <= rt->b3_1_upper ; b2++)
+		{
+			for (b3 = rt->b3_2_lower ; b3 <= rt->b3_2_upper ; b3++)
+			{
+				for (b4 = rt->b3_3_lower ; b4 <= rt->b3_3_upper ; b4++)
+				{
+					uint32 r = pg_mb_radix_conv(rt, 3, 0, b2, b3, b4);
+					if (r != 0)
+						print_one_line(out,
+							(((uint32)b2) << 16) | (((uint32)b3) << 8) | b4,
+							r);
+				}
+			}
+		}
+	}
+	if (rt->b4_1_lower > 0 || rt->b4_1_upper > 0 ||
+		rt->b4_2_lower > 0 || rt->b4_2_upper > 0 ||
+		rt->b4_3_lower > 0 || rt->b4_3_upper > 0 ||
+		rt->b4_4_lower > 0 || rt->b4_4_upper > 0)
+	{
+		for (b1 = rt->b4_1_lower ; b1 <= rt->b4_1_upper ; b1++)
+		{
+			for (b2 = rt->b4_2_lower ; b2 <= rt->b4_2_upper ; b2++)
+			{
+				for (b3 = rt->b4_3_lower ; b3 <= rt->b4_3_upper ; b3++)
+				{
+					for (b4 = rt->b4_4_lower ; b4 <= rt->b4_4_upper ; b4++)
+					{
+						uint32 r = pg_mb_radix_conv(rt, 4, b1, b2, b3, b4);
+						if (r != 0)
+							print_one_line(out,
+								(((uint32)b1) << 24) | (((uint32)b2) << 16) |
+								(((uint32)b3) << 8) | b4,
+								r);
+					}
+				}
+			}
+		}
+	}
+}
+
+int
+main(void)
+{
+	struct mappair *mappair;
+
+	for (mappair = &mappairs[0] ; mappair->name ; mappair++)
+	{
+		char fname[32];
+		FILE *out;
+
+		snprintf(fname, 32, "%s.dump", mappair->name);
+		out = fopen(fname, "w");
+		if (out == NULL)
+		{
+			fprintf(stderr, "failed to open dump output file: %s\n", fname);
+			exit(1);
+		}
+
+		dump_radix_tree(out, mappair->rt);
+
+		fclose(out);
+	}
+
+	return 0;
+}
-- 
2.9.2

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to