Hi

> > > There's a whitespace-only hunk that shouldn't be included.
> > >
> > > I don't agree with the single-column/single-row restriction on these.
> I
> > > can certainly see a case where someone might want to, say, dump out a
> > > bunch of binary integers into a file for later processing.
> > >
> > > The tab-completion for 'gstore' wasn't correct (you didn't include the
> > > double-backslash).  The patch also has conflicts against current master
> > > now.
> > >
> > > I guess my thinking about moving this forward would be to simplify it
> to
> > > just '\gb' which will pull the data from the server side in binary
> > > format and dump it out to the filename or command given.  If there's a
> > > new patch with those changes, I'll try to find time to look at it.
> >
> > ok I'll prepare patch
>
> Great, thanks!
>

I rewrote these patches - it allows binary export/import from psql and the
code is very simple. The size of the patch is bigger due including 4KB
binary file (in hex format 8KB).

What is done:

create table foo foo(a bytea);

-- import
insert into foo values($1)
\gloadfrom ~/xxx.jpg bytea

-- export
\pset format binary
select a from foo
\g ~/xxx2.jpg

tested on import 55MB binary file

Comments, notes?

Available import formats are limited to text, bytea, xml - these formats
are safe for receiving data via recv function.

Regards

Pavel



>
> Stephen
>
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 2a9c412020..f26d406f89 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1945,6 +1945,38 @@ CREATE INDEX
 
 
       <varlistentry>
+        <term><literal>\gloadfrom <replaceable class="parameter">filename</replaceable> <optional> <replaceable class="parameter">format</replaceable> </optional> </literal></term>
+
+        <listitem>
+        <para>
+         Sends the current query input buffer to the server. The current
+         query should to have one query parameter <literal>$1</literal>.
+         The content of <literal>filename</literal> file will be used as
+         the value of this parameter.
+        </para>
+
+        <para>
+         When <literal>format</literal> is not specified, then data are
+         passed in text format. When format is specified, then data are
+         passed in binary format. The available formats are:
+         <literal>text</literal>, <literal>bytea</literal>
+         or <literal>xml</literal> type. In the example the XML document is 
+         imported to table <structname>my_table</>:
+<programlisting>
+=&gt; <userinput>CREATE TABLE my_table(id serial, doc xml);</>
+=&gt; <userinput>INSERT INTO my_table(doc) VALUES($1) RETURNING id</>
+-&gt; <userinput>\gloadfrom ~/Documents/data.xml xml</>
+ id 
+----
+  1
+(1 row)
+</programlisting>
+        </para>
+        </listitem>
+      </varlistentry>
+
+
+      <varlistentry>
         <term><literal>\gset [ <replaceable class="parameter">prefix</replaceable> ]</literal></term>
 
         <listitem>
@@ -2366,8 +2398,8 @@ lo_import 152801
           <literal>aligned</literal>, <literal>wrapped</literal>,
           <literal>html</literal>, <literal>asciidoc</literal>,
           <literal>latex</literal> (uses <literal>tabular</literal>),
-          <literal>latex-longtable</literal>, or
-          <literal>troff-ms</literal>.
+          <literal>latex-longtable</literal>, <literal>troff-ms</literal> or
+          <literal>binary</literal>.
           Unique abbreviations are allowed.  (That would mean one letter
           is enough.)
           </para>
@@ -2404,6 +2436,12 @@ lo_import 152801
           also requires the <application>LaTeX</application>
           <literal>longtable</literal> and <literal>booktabs</> packages.
           </para>
+
+          <para>
+          The <literal>binary</> format is simply output values in
+          binary format.
+          </para>
+
           </listitem>
           </varlistentry>
 
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 4f4a0aa9bd..51ed3df58c 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -28,6 +28,7 @@
 #endif
 
 #include "catalog/pg_class.h"
+#include "catalog/pg_type.h"
 #include "portability/instr_time.h"
 
 #include "libpq-fe.h"
@@ -936,6 +937,50 @@ exec_command(const char *cmd,
 		status = PSQL_CMD_SEND;
 	}
 
+	/*
+	 * \gloadfrom filename -- send query and use content of file as parameter
+	 */
+	else if (strcmp(cmd, "gloadfrom") == 0)
+	{
+		char	   *fmt = NULL;
+		char	   *fname = psql_scan_slash_option(scan_state,
+												   OT_FILEPIPE, NULL, false);
+
+		if (!fname)
+		{
+			psql_error("\\%s: missing required argument\n", cmd);
+			success = false;
+		}
+		else
+		{
+			/* try to get separate format arg */
+			fmt = psql_scan_slash_option(scan_state,
+										OT_NORMAL, NULL, true);
+
+			if (fmt)
+			{
+				if (strcmp(fmt, "text") == 0)
+					pset.gloadfrom_fmt = TEXTOID;
+				else if (strcmp(fmt, "bytea") == 0)
+					pset.gloadfrom_fmt = BYTEAOID;
+				else if (strcmp(fmt, "xml") == 0)
+					pset.gloadfrom_fmt = XMLOID;
+				else
+				{
+					psql_error("\\%s: only [text, bytea, xml] format can be specified\n", cmd);
+					success = false;
+				}
+			}
+			else
+				pset.gloadfrom_fmt = 0;		/* UNKNOWNOID */
+
+			expand_tilde(&fname);
+			pset.gloadfrom = pg_strdup(fname);
+		}
+		free(fname);
+		status = PSQL_CMD_SEND;
+	}
+
 	/* \gset [prefix] -- send query and store result into variables */
 	else if (strcmp(cmd, "gset") == 0)
 	{
@@ -2518,6 +2563,9 @@ _align2string(enum printFormat in)
 		case PRINT_TROFF_MS:
 			return "troff-ms";
 			break;
+		case PRINT_BINARY:
+			return "binary";
+			break;
 	}
 	return "unknown";
 }
@@ -2589,9 +2637,11 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			popt->topt.format = PRINT_LATEX_LONGTABLE;
 		else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
 			popt->topt.format = PRINT_TROFF_MS;
+		else if (pg_strncasecmp("binary", value, vallen) == 0)
+			popt->topt.format = PRINT_BINARY;
 		else
 		{
-			psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms\n");
+			psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms, binary\n");
 			return false;
 		}
 	}
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index e9d4fe6786..d9a52d17e6 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -12,6 +12,7 @@
 #include <limits.h>
 #include <math.h>
 #include <signal.h>
+#include <sys/stat.h>
 #ifndef WIN32
 #include <unistd.h>				/* for write() */
 #else
@@ -32,6 +33,7 @@
 static bool ExecQueryUsingCursor(const char *query, double *elapsed_msec);
 static bool command_no_begin(const char *query);
 static bool is_select_command(const char *query);
+static bool read_file(char *fname, PQExpBuffer rawbuf);
 
 
 /*
@@ -1285,7 +1287,8 @@ SendQuery(const char *query)
 	}
 
 	if (pset.fetch_count <= 0 || pset.gexec_flag ||
-		pset.crosstab_flag || !is_select_command(query))
+		pset.crosstab_flag || !is_select_command(query) ||
+		pset.popt.topt.format == PRINT_BINARY || pset.gloadfrom)
 	{
 		/* Default fetch-it-all-and-print mode */
 		instr_time	before,
@@ -1294,7 +1297,56 @@ SendQuery(const char *query)
 		if (pset.timing)
 			INSTR_TIME_SET_CURRENT(before);
 
-		results = PQexec(pset.db, query);
+		/*
+		 * PQexecParams disallow multiple commands often
+		 * used by -c option. From compatibility reason the
+		 * PQexecParams is used only when it is necessary.
+		 */
+		if (pset.popt.topt.format == PRINT_BINARY || pset.gloadfrom)
+		{
+			if (pset.gloadfrom)
+			{
+				PQExpBufferData		rawbuf;
+
+				initPQExpBuffer(&rawbuf);
+
+				if (read_file(pset.gloadfrom, &rawbuf))
+				{
+					Oid paramTypes[1];
+					const char *paramValues[1];
+					int paramLengths[1];
+					int paramFormats[1];
+
+					paramTypes[0] = pset.gloadfrom_fmt;
+					paramFormats[0] = pset.gloadfrom_fmt != 0 ? 1 : 0;
+					paramValues[0] = rawbuf.data;
+					paramLengths[0] = rawbuf.len;
+
+					results = PQexecParams(pset.db, query,
+											  1,
+											  paramTypes,
+											  paramValues,
+											  paramLengths,
+											  paramFormats,
+											  pset.popt.topt.format == PRINT_BINARY);
+				}
+				else
+				{
+					OK = false;
+					results = NULL;
+				}
+
+				termPQExpBuffer(&rawbuf);
+			}
+			else
+			{
+				results = PQexecParams(pset.db, query,
+										  0, NULL, NULL, NULL, NULL,
+										  pset.popt.topt.format == PRINT_BINARY);
+			}
+		}
+		else
+			results = PQexec(pset.db, query);
 
 		/* these operations are included in the timing result: */
 		ResetCancelConn();
@@ -1418,6 +1470,13 @@ sendquery_cleanup:
 		pset.gfname = NULL;
 	}
 
+	/* reset \gloadfrom input-from-filename trgger */
+	if (pset.gloadfrom)
+	{
+		free(pset.gloadfrom);
+		pset.gloadfrom = NULL;
+	}
+
 	/* reset \gx's expanded-mode flag */
 	pset.g_expanded = false;
 
@@ -2152,3 +2211,53 @@ recognized_connection_string(const char *connstr)
 {
 	return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL;
 }
+
+/*
+ * read file into buffer
+ */
+static bool
+read_file(char *fname, PQExpBuffer rawbuf)
+{
+	FILE	   *fd;
+	bool	   result = false;
+
+	fd = fopen(fname, PG_BINARY_R);
+	if (fd)
+	{
+		struct stat		fst;
+
+		if (fstat(fileno(fd), &fst) != -1)
+		{
+			if (S_ISREG(fst.st_mode))
+			{
+				if (fst.st_size <= ((int64) 1024) * 1024 * 1024)
+				{
+					size_t				size;
+					char				buf[512];
+
+					while ((size = fread(buf, 1, sizeof(buf), fd)) > 0)
+						appendBinaryPQExpBuffer(rawbuf, buf, size);
+
+					if (ferror(fd))
+						psql_error("%s: %s\n", fname, strerror(errno));
+					else if (PQExpBufferBroken(rawbuf))
+						psql_error("out of memory\n");
+					else
+						result = true;
+				}
+				else
+					psql_error("%s is too big (greather than 1GB)\n", fname);
+			}
+			else
+				psql_error("%s is not regular file\n", fname);
+		}
+		else
+			psql_error("%s: %s\n", fname, strerror(errno));
+
+		fclose(fd);
+	}
+	else
+		psql_error("%s: %s\n", fname, strerror(errno));
+
+	return result;
+}
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index ba14df0344..17d0469697 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -167,7 +167,7 @@ slashUsage(unsigned short int pager)
 	 * Use "psql --help=commands | wc" to count correctly.  It's okay to count
 	 * the USE_READLINE line even in builds without that.
 	 */
-	output = PageOutput(113, pager ? &(pset.popt.topt) : NULL);
+	output = PageOutput(114, pager ? &(pset.popt.topt) : NULL);
 
 	fprintf(output, _("General\n"));
 	fprintf(output, _("  \\copyright             show PostgreSQL usage and distribution terms\n"));
@@ -175,6 +175,7 @@ slashUsage(unsigned short int pager)
 	fprintf(output, _("  \\g [FILE] or ;         execute query (and send results to file or |pipe)\n"));
 	fprintf(output, _("  \\gx [FILE]             as \\g, but forces expanded output mode\n"));
 	fprintf(output, _("  \\gexec                 execute query, then execute each value in its result\n"));
+	fprintf(output, _("  \\gloadfrom FILE [fmt]  execute query, use content of FILE as query parameter\n"));
 	fprintf(output, _("  \\gset [PREFIX]         execute query and store results in psql variables\n"));
 	fprintf(output, _("  \\q                     quit psql\n"));
 	fprintf(output, _("  \\crosstabview [COLUMNS] execute query and display results in crosstab\n"));
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 70ff1812c8..8078890a10 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -91,6 +91,9 @@ typedef struct _psqlSettings
 	printQueryOpt popt;
 
 	char	   *gfname;			/* one-shot file output argument for \g */
+	char	   *gloadfrom;		/* one-shot file input argument for \gloadfrom */
+	Oid		    gloadfrom_fmt;	/* one-shot data file format UNKNOWNOID,
+								 * TEXTOID, BYTEAOID or XMLOID */
 	bool		g_expanded;		/* one-shot expanded output requested via \gx */
 	char	   *gset_prefix;	/* one-shot prefix argument for \gset */
 	bool		gexec_flag;		/* one-shot flag to execute query's results */
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f7494065de..3eb24c4502 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1410,8 +1410,9 @@ psql_completion(const char *text, int start, int end)
 		"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\drds", "\\ds", "\\dS",
 		"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy",
 		"\\e", "\\echo", "\\ef", "\\encoding", "\\errverbose", "\\ev",
-		"\\f", "\\g", "\\gexec", "\\gset", "\\gx", "\\h", "\\help", "\\H",
-		"\\i", "\\ir", "\\l", "\\lo_import", "\\lo_export", "\\lo_list",
+		"\\f", "\\g", "\\gexec", "\\gloadfrom", "\\gset", "\\gx",
+		"\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
+		"\\lo_import", "\\lo_export", "\\lo_list",
 		"\\lo_unlink", "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q",
 		"\\qecho", "\\r", "\\s", "\\set", "\\setenv", "\\sf", "\\sv", "\\t",
 		"\\T", "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!",
@@ -3422,7 +3423,7 @@ psql_completion(const char *text, int start, int end)
 		{
 			static const char *const my_list[] =
 			{"unaligned", "aligned", "wrapped", "html", "asciidoc",
-			"latex", "latex-longtable", "troff-ms", NULL};
+			"latex", "latex-longtable", "troff-ms", "binary", NULL};
 
 			COMPLETE_WITH_LIST_CS(my_list);
 		}
@@ -3443,8 +3444,8 @@ psql_completion(const char *text, int start, int end)
 	}
 	else if (TailMatchesCS2("\\set", MatchAny))
 	{
-		if (TailMatchesCS1("AUTOCOMMIT|ON_ERROR_STOP|QUIET|"
-						   "SINGLELINE|SINGLESTEP"))
+		if (TailMatchesCS1("AUTOCOMMIT|BINARY_PARAM"
+						   "ON_ERROR_STOP|QUIET|SINGLELINE|SINGLESTEP"))
 			COMPLETE_WITH_LIST_CS2("on", "off");
 		else if (TailMatchesCS1("COMP_KEYWORD_CASE"))
 			COMPLETE_WITH_LIST_CS4("lower", "upper",
@@ -3469,7 +3470,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
 	else if (TailMatchesCS1("\\cd|\\e|\\edit|\\g|\\i|\\include|"
 							"\\ir|\\include_relative|\\o|\\out|"
-							"\\s|\\w|\\write|\\lo_import"))
+							"\\s|\\w|\\write|\\lo_import|\\gloadfrom"))
 	{
 		completion_charp = "\\";
 		matches = completion_matches(text, complete_from_files);
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index 9180b90004..829f9ebc83 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -3293,6 +3293,40 @@ printQuery(const PGresult *result, const printQueryOpt *opt,
 	if (cancel_pressed)
 		return;
 
+	/* direct print in binary format */
+	if (opt->topt.format == PRINT_BINARY)
+	{
+		/* check format */
+		for (c = 0; c < PQnfields(result); c++)
+			if (PQfformat(result, c) == 0)
+			{
+				fprintf(stderr, _("invalid data format (internal error)"));
+				exit(EXIT_FAILURE);
+			}
+
+		for (r = 0; r < PQntuples(result); r++)
+		{
+			for (c = 0; c < PQnfields(result); c ++)
+			{
+				if (!PQgetisnull(result, r, c))
+				{
+					int		size = PQgetlength(result, r, c);
+					char   *value = PQgetvalue(result, r, c);
+					bool	success;
+
+					success = fwrite(value, 1, size, fout) == size;
+					if (!success)
+					{
+						fprintf(stderr, _("write error (internal error): %s"),
+								strerror(errno));
+						exit(EXIT_FAILURE);
+					}
+				}
+			}
+		}
+		return;
+	}
+
 	printTableInit(&cont, &opt->topt, opt->title,
 				   PQnfields(result), PQntuples(result));
 
diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h
index d89b6febcb..64ea406d5c 100644
--- a/src/include/fe_utils/print.h
+++ b/src/include/fe_utils/print.h
@@ -33,7 +33,8 @@ enum printFormat
 	PRINT_ASCIIDOC,
 	PRINT_LATEX,
 	PRINT_LATEX_LONGTABLE,
-	PRINT_TROFF_MS
+	PRINT_TROFF_MS,
+	PRINT_BINARY
 	/* add your favourite output format here ... */
 };
 
diff --git a/src/test/regress/data/logo.data b/src/test/regress/data/logo.data
new file mode 100644
index 0000000000..b324eb2178
--- /dev/null
+++ b/src/test/regress/data/logo.data
@@ -0,0 +1 @@
+\x47494638396164003a00e600002b89bb007bb3005a9b93cfe3006595008ab2458ab2eef5f9008abb0094c20054940079a8a4d7e888bad699c2d83492be297aaa45a5c80065aa77a8c577bad40085b1dbebf30083b90082ac006ba4005da00076a9007ca9bbdbeac6e6f10068adcce3ef0074a40079ad1475acbbd3e40075ac429bc40081b00085ae66a9cb0074b10090be1b7bb3006da952a4c90061a20064a57cc3dd0071ad0061a5f8fcfd0071a8bce1ee006baf0085b6006daf0081b6b1dceb007dae007db700548d126da80068a91482b665b8d65ab3d5005698007fab0058960078a8ccddea004e8c0c65a2669abc0066a00c6dad66a0c24480ac77b2d1004f92bbd7e8aad0e40c68a7aacbde0560a2246ea152accf77adcf66afcf11689fbbcfe20664a20767a9e0f1f6115f96085e9f3d3d3dffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021f90400000000002c0000000064003a000007ff806282838485868788898a8b8c8d8a092b91910894083897973a22359c9c2d192f46a2a3a4a20a46a70aaaabacadab464c404c19b435013cb701273d273abe989795082bc3922b09c80982c8c6c294983d25d29d194c0246d7a5a5a7a8ddaca8aeab02b1b4b425b93cbc3abd17c0cec691c9c8cb9092ce983ad22535329cd6d8da027a1b984a15b8561a320029d742448087bb7ae9c03131983062c6981540b10cdebd4b224ac810c9cf9a806b27491119888a88ab243093847389eac5c2852d5ae0d2d5c397af0bed705c2c26a90086a318e879144631a43e192d3408207032a5001faa562af011856b14054a942888f2e38189080f9424f9da8da628269fff7236e429b122a677933014298294a31848f52609bb20c2e9481930a8564599644b0c1b1d76d8b011830504063b32eff87280f2801d1d06b0f84aa4b469231a5a0091db22408f9e3e81debd88a30887bd7c912ab547ac922615fa5464902a75b10f16166240d0a0800a002c340e985012c5c8081703188c8019c6850717594b1b310d236e4e113d78f8fc69b1120e1e1ce2e3469af42fb3669502885011123893171a04589c023f58f0804ca624f1c0003f24b1122a6b3d60a04c4928614304513c281e6aace5f45a6cedb4e31e070bc427df7c47d113586f945ca01f7fc0b500e054020c880505a7540596052c240110404424018105006498040b1e88f5e0ff2802ac26970cae8178010253e240e202259a885b6ef525b314020f05006309a01010608d553150e4620a4410838f5589720d115100604318aa08b0c308dc9022c00b1dcab09e0eb2bd77c4a15866791b8a5d7ac91b9861ee27020c2f0058e9995dd8008002689e64c381a62d26804b49c430c45761ec1985a827a5d6025432c8d01350b29db0c106871e8125892772d9e87df6e010a99825546aa9800258c88202677a0a010b0f0080928e2c4430800761443182073f284004ab0264006bac01104aab081b84706bae89f6ba578af601db9b0e618a29828cc61e2b40173b6c4adcbe5fece0c1183460f16d8d0a3c70c018072459e714a3822b000c32e410abff0c2a98dbc3adb7aa9babae596eb9d7092a3a4acc6bf506d0c27ff95e2a400c0f307b2615dcb270c0171e5851a306510c70adb5746281c5aa12537c31c684f2c071baebb21bf296f0cab3220228d70b04a52d57daa610a80968c500a7281106833b2b3080090ab030c0aa9a725ad5bf1abc7074ace995b081dd4b7facab891cf0c065c9c0525df5435763dd3211765a81ac150ca02640cf00744d0416032401c0da2cec1046ab68c23df748772fdd31ae4e6bc9175f80df27b80e3d84290b0cb01b0e83004dd8f043dc008ec0c09fcc0df0c0ceb473ebc5daa6ca2ce0f101aa8071ac19d41092e8a47fbc6baf514b5d0f45af551d7bec2f184e84ef7f020840ffe3026ab7b306460c11c3d73f78d0c4f9c80ba8bcf2389580eed21e976e7a6ea9d77301ebac734d006050b8ed756f0602a01c116690bb1d280e71390b10808850bb0708c15444885ffc9427035a2c6403f7c31fe9da653addc4cb7aff635df67a200b2014707b1ad896173430831a32c0055f8981c12c35030d1021023863001532a84109be4079aa294761a0d73490edcf84154080f556001415664f35af7b210c10784322504a002338801000f0851110a16501dac1181e10052bcc306e1234e20c54909372302184d04394a216451f4154e08f529447152fb04219b8d085db8b9d061e10c11910e1013b18c20e68308011d0b0523dfc010392a33edb05a8ff87a08c9b04a052478580308f47c0150917f5aefafcf18f2718063268454815aae090b82420ec5e300306188c0826f00000326782cf0880810c24c2102af98021346c8659ab14c5e4a2443c3611517c839a2b61f9ca61506990afb9252e5d288172c240021a408e593c10030f30c00454b081072656431828f30bd91940043e59c37ed6b07bb12a650b42c7b1544a6f7a7c34210a5e5981135420133da0554f5e334e5c4a40971a00c00e1850ade40c60320398d8167b180313b0600408a4a13ffde92a6a02a10604159d1ef9c64a2832f48f14b1956b247a811ce4a4a2872ca70684aa81200000004d28a6002e0a030d7c60072cc8603d61d74feecd20a0a5ffb41b1e53394284be2b377eb969432bb00efb3924a284a4630b3e005472321508e83c93091830d473a6d3062ca8ebf66640d52d6a000858fd44064088b76b824c51ad3c4a586f8a8313e0a0026675886b5e93831bdc60ad1fc86c6681c0d60f94f3b3e59c0124872a548d36a1861298416a57ab5a09f0f255a414ac59f316bd55a20805db64e8634152987a85330795b5ac70354bdce2ce40a3a4fd404607f081d68216b40c1c65603fb144dace747fbef223631ffa9edefa5605976d81702d5bdcf296330736582d3a853004d23ef7b3fd6c0107a9e93c8e89c0a0072d2197162bd64c3844b293ed810c2e3bde0293b7b8e58c240d3560020b044102e685efff0c80a082f9d6d17ea864573619c55fc63e563f616a1dca7c6a60039b37083660808a853983f26696a97c5dde7441684dbded519b28e8f043717a891300f821d9036f894bfc811b6876064d88001600504e177b16c637a87040a19281d9a212a127a24f8efd5880ed62e2c701ee0178810bdcf10677c8cf2d7279e17ad119c857cab16d4861ee5b5044ed0dbb8addb2182ad065dd72b7b13f5ea1986f50d9320f99c8e38df045dfac0200a4000a5048c108acbc81074081025078c002eefcc43c87b5cf111883a847dd01218059d02a30f4998f7a68231bd9c59f25608555d080518bfa002998b3846c3d0603ed6a0c14c0718efdd2e52e87da0113c8c2041aff6081314021c482665daa094de61c48410a1268f570115cce2857180a6320010460f204241c00022250d8019600061f806102073880a63930860964402f7d19b6208a5d81501b20044708c102c278800cf8367b841473b52b2b051210e1cc4486b50472306b1574600c6050c06a3260827a87e0e210f00113041e0200843b04f4b6f77e874dec02187b0c0628c2427150001b8ce10522d00208440d022d648f02031b0308a000800ec49b040dc80100a6c0731734a0013778fa08b22005008cc0010b3bc0141e50e18b83e1a555168109ae00813138c00700dfb4ae1c30060814c1e32bd7b7185cce677f7360c738e00c01626076033ca1d60de80105c66002ff18286102637042162c6081092ce10af19ec0139660810390400052400212a430812b983b0b063080b959a082148c0109296081f3ee5b03d32f8100a5d382c7eb7d6fc56280e5fb767901423d8108f85e08176f40d9a1008b5865610c2ca0000834a082d764e10933200117a2a001b63f21431ab8c218b8a00029d43b0a517002cc8920811684d101afcac2c21836050a04e108e07e4206049ea80574dcde70bf3dcbf5acfbddf39a610d4000a6070106f7102637012e607611f01a3d95031de0701f200507100533e06a52307d12980473340063f00426f0812600021620002d500361700513e000cd76002e3078f2775825727f19e0715a867b73a77bbc17ff7aa14700041002834700fa2159f576032e40023c4701afd101523047e116059a75030d27000f48040f7171ff37063e50828355034c40004bd06ba6370169373d83b7043328861ca07f2c5700b9e772feb600b871773830783fd014221004f506040120032f60008807053da0843010880730032bf4802fa0841a202617a70a58111357200529603f0b705f47b073da47020490285a30001c707157100234e8691bc18637e88630277337d5714ef050271000b2070150a0056122030dd7024af80201307806206241700052a0010fc87cb4d6811cd47a92d66b1950184720020b50793ec0764e50220ba03046e80046907221e06928a07b6de87f0670770ce5ff5046e7028f85055ae70353700000f0104160010e908848a08bbf78005060025af005164002c2c88f15667248300235d0021d97054c506b24f000ce08006cd7003e10044860762e60022e707107b00504f07624706914d09114d08d2ef78dfe860162550141c076a3e6005bf0024160845270711db00507296a1d100027b93020e0025cc08fc35802ca63025c300652b0730d90044cc001ea676b0790053eb08937696b55506f69788563b000de788a2e870119599215800223107a1899013c10125bf004067005a8710e00f0046070442a100a9c620155200025701222d10f4c70054fc09622775f22400010b0974fe0034d09322140007e670046e0034e10ff907ac18390099957d97fbac7950e75023ec601bdd00b3c200d25280d4e5182bfd80100a00227d9811a201224d10982055374b64421307ff47758f11102b67914234000f4a186a5189273b70294d967627599c4e95827c0039da90fca290dbb766b4ee003e2c20fac395025c00185616b1b606b473006dbb90063406fa3f676a38601b68602a3d67ffb069cc1699998599ced890bcba99c1910988329729de00935603fd63967dc2902dcc99ddd5995df39a0273206473106e6c97263e0720bea9bea49997c5692eed99e98b90ec7e914f9b90ffd500dcd739ff95918f0316795a89d002aa0de496fe039067b319ee6296a39d6a00d6a8a05009c0f5a99c209c44b98890114baa3ef890bcfb30f9d803773b69f855189ceb89dec52a2274aa02afa2e069aa008ba500500a39339a3c1c96f7fb4509859013acaa3ef799c608a9c622aa6206a9d446aa4b902a0ba626bde696be2296ae4797b086a6b532a6ae82906347aa574f74a0b459214daa5ef5904c739a6848a9c7de38c22b09f95b8696ac7a8f58765dac48d39c6677a6a8a795aa3fdc7503976023a0aa82720a83c00a64550a8863a96448aa88b8a2530d82e7bc44a89c58dbda9a78e30abb45aabb67aab821008003b
diff --git a/src/test/regress/input/psql_export_import.source b/src/test/regress/input/psql_export_import.source
new file mode 100644
index 0000000000..a6545c6de5
--- /dev/null
+++ b/src/test/regress/input/psql_export_import.source
@@ -0,0 +1,29 @@
+-- export/import binary varlena objects
+create table test_bin_objects(id integer, doc bytea);
+insert into test_bin_objects values(1, E'\\xDE00ADBEEF');
+
+\pset format binary
+select doc from test_bin_objects where id = 1
+\g results/varlenatest.bin
+
+insert into test_bin_objects values(2, $1)
+\gloadfrom results/varlenatest.bin bytea
+
+\pset format aligned
+select id, doc, md5(doc) from test_bin_objects;
+
+truncate test_bin_objects;
+
+insert into test_bin_objects values(1, $1)
+\gloadfrom '@abs_srcdir@/data/logo.data'
+
+\pset format binary
+select doc from test_bin_objects where id = 1
+\g results/100x58_1.gif
+
+insert into test_bin_objects values(2, $1)
+\gloadfrom results/100x58_1.gif bytea
+
+\pset format aligned
+-- print when md5 is unexpected (result should be empty)
+select id, md5(doc) from test_bin_objects where md5(doc) <> '24da0c4de68bf19682344f8b060faeb5';
diff --git a/src/test/regress/output/psql_export_import.source b/src/test/regress/output/psql_export_import.source
new file mode 100644
index 0000000000..bd7dbb3692
--- /dev/null
+++ b/src/test/regress/output/psql_export_import.source
@@ -0,0 +1,31 @@
+-- export/import binary varlena objects
+create table test_bin_objects(id integer, doc bytea);
+insert into test_bin_objects values(1, E'\\xDE00ADBEEF');
+\pset format binary
+select doc from test_bin_objects where id = 1
+\g results/varlenatest.bin
+insert into test_bin_objects values(2, $1)
+\gloadfrom results/varlenatest.bin bytea
+\pset format aligned
+select id, doc, md5(doc) from test_bin_objects;
+ id |     doc      |               md5                
+----+--------------+----------------------------------
+  1 | \xde00adbeef | 70afdd78c75bfb6e76781d3785858b66
+  2 | \xde00adbeef | 70afdd78c75bfb6e76781d3785858b66
+(2 rows)
+
+truncate test_bin_objects;
+insert into test_bin_objects values(1, $1)
+\gloadfrom '@abs_srcdir@/data/logo.data'
+\pset format binary
+select doc from test_bin_objects where id = 1
+\g results/100x58_1.gif
+insert into test_bin_objects values(2, $1)
+\gloadfrom results/100x58_1.gif bytea
+\pset format aligned
+-- print when md5 is unexpected (result should be empty)
+select id, md5(doc) from test_bin_objects where md5(doc) <> '24da0c4de68bf19682344f8b060faeb5';
+ id | md5 
+----+-----
+(0 rows)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index ea7b5b4aa2..053ee03ed3 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -89,7 +89,7 @@ test: brin gin gist spgist privileges init_privs security_label collate matview
 # ----------
 # Another group of parallel tests
 # ----------
-test: alter_generic alter_operator misc psql async dbsize misc_functions sysviews tsrf
+test: alter_generic alter_operator misc psql psql_export_import async dbsize misc_functions sysviews tsrf
 
 # rules cannot run concurrently with any test that creates a view
 test: rules psql_crosstab amutils
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index cf48ea7cc8..32aaa30e15 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -124,6 +124,7 @@ test: alter_generic
 test: alter_operator
 test: misc
 test: psql
+test: psql_export_import
 test: async
 test: dbsize
 test: misc_functions
-- 
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