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>
+=> <userinput>CREATE TABLE my_table(id serial, doc xml);</>
+=> <userinput>INSERT INTO my_table(doc) VALUES($1) RETURNING id</>
+-> <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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers