From: Nikita Glukhov <n.gluhov@postgrespro.ru>
To: Tom Lane <tgl@sss.pgh.pa.us>
To: Robert Haas <robertmhaas@gmail.com>
Cc: Andres Freund <andres@anarazel.de>
Cc: Jonathan S. Katz <jkatz@postgresql.org>
Cc: Andrew Dunstan <andrew@dunslane.net>
Cc: Amit Langote <amitlangote09@gmail.com>
Cc: Alvaro Herrera <alvherre@alvh.no-ip.org>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Cc: Michael Paquier <michael@paquier.xyz>
Cc: John Naylor <john.naylor@enterprisedb.com>
Subject: Re: SQL/JSON features for v15
Date: Wed, 31 Aug 2022 23:39:31 +0300
Message-ID: <379e5365-9670-e0de-ee08-57ba61cbc976@postgrespro.ru> (raw)
In-Reply-To: <14814.1661966096@sss.pgh.pa.us>
References: <CA+HiwqH8gTp2uNN3QtgeOSgHhZUZz1=0U+JObJJUmEoch_269Q@mail.gmail.com>
<20220830092008.6dbublx6la226zis@alvherre.pgsql>
<CA+HiwqFvP23i3kTHt6TW4FqO6he1YSJXeyGOdFV_YbP=xeS99A@mail.gmail.com>
<f54ebd2b-0e67-d1c6-4ff7-5d732492d1a0@postgrespro.ru>
<CA+HiwqHLVPdA7e3Y-S5giKPsqQPf8M0nuvgz8+3D8GjQexXLYA@mail.gmail.com>
<CA+HiwqECHA0aUi0Bo3tdYTJ27i2MRWUZ5BewQoO0WgRvRXQO-Q@mail.gmail.com>
<abd31e0b-56aa-044f-6700-8a1c1bba87f1@dunslane.net>
<2276d20d-43ff-f9f6-5c9c-c2875739e66c@postgresql.org>
<20220831154916.pgspuz3bp4427int@awork3.anarazel.de>
<4151123.1661961884@sss.pgh.pa.us>
<13351.1661965592@sss.pgh.pa.us>
<CA+TgmobX2330ByUrrSo1SbcoRPYBbZ1bp3h54hLsxsd1AeBocQ@mail.gmail.com>
<14814.1661966096@sss.pgh.pa.us>
On 31.08.2022 20:14, Tom Lane wrote:
> Robert Haas<robertmhaas@gmail.com> writes:
>> On Wed, Aug 31, 2022 at 1:06 PM Tom Lane<tgl@sss.pgh.pa.us> wrote:
>>> The currently proposed patchset hacks up a relatively small number
>>> of core datatypes to be able to do that. But it's just a hack
>>> and there's no prospect of extension types being able to join
>>> in the fun. I think where we need to start, for v16, is making
>>> an API design that will let any datatype have this functionality.
>>>
>>> (I don't say that we'd convert every datatype to do so right away;
>>> in the long run we should, but I'm content to start with just the
>>> same core types touched here.) Beside the JSON stuff, there is
>>> another even more pressing application for such behavior, namely
>>> the often-requested COPY functionality to be able to shunt bad data
>>> off somewhere without losing the entire transfer. In the COPY case
>>> I think we'd want to be able to capture the error message that
>>> would have been issued, which means the current patches are not
>>> at all appropriate as a basis for that API design: they're just
>>> returning a bool without any details.
>>>
>> I would be in favor of making more of an effort than just a few token
>> data types. The initial patch could just touch a few, but once the
>> infrastructure is in place we should really make a sweep through the
>> tree and tidy up.
> Sure, but my point is that we can do that in a time-extended fashion
> rather than having a flag day where everything must be updated.
> The initial patch just needs to update a few types as proof of concept.
>
And here is a quick POC patch with an example for COPY and float4:
=# CREATE TABLE test (i int, f float4);
CREATE TABLE
=# COPY test (f) FROM stdin WITH (null_on_error (f));
1
err
2
\.
COPY 3
=# SELECT f FROM test;
f
---
1
2
(3 rows)
=# COPY test (i) FROM stdin WITH (null_on_error (i));
ERROR: input function for datatype "integer" does not support error handling
PG_RETURN_ERROR() is a reincarnation of ereport_safe() macro for returning
ErrorData, which was present in older versions (~v18) of SQL/JSON patches.
Later it was replaced with `bool *have_error` and less magical
`if (have_error) ... else ereport(...)`.
Obviously, this needs a separate thread.
--
Nikita Glukhov
Postgres Professional:http://www.postgrespro.com
The Russian Postgres Company
Attachments:download all (5 files, .tar.gz)0001-Introduce-PG_RETURN_ERROR-and-FuncCallError-node.patch (text/x-patch, 2.0K) download
From 537e65e1ebcccdf4a760d3aeeeea743c88611e7c Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 31 Aug 2022 22:24:33 +0300
Subject: [PATCH 1/5] Introduce PG_RETURN_ERROR and FuncCallError node
---
src/include/nodes/execnodes.h | 7 +++++++
src/include/utils/elog.h | 25 +++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.hindex 01b1727fc09..b401d354656 100644--- a/src/include/nodes/execnodes.h+++ b/src/include/nodes/execnodes.h@@ -2729,4 +2729,11 @@ typedef struct LimitState
TupleTableSlot *last_slot; /* slot for evaluation of ties */
} LimitState;
+typedef struct FuncCallError+{+ NodeTag type;+ ErrorData *error; /* place where function should put+ * error data instead of throwing it */+} FuncCallError;+
#endif /* EXECNODES_H */
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.hindex 56398176901..5fd3deed61f 100644--- a/src/include/utils/elog.h+++ b/src/include/utils/elog.h@@ -159,6 +159,31 @@
#define ereport(elevel, ...) \
ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__)
+/*+ * PG_RETURN_ERROR() -- special macro for copying error info into the+ * FuncCallError node, if it was as FunctionCallInfo.context,+ * instead of throwing it with ordinary ereport().+ *+ * This is intended for handling of errors of categories like+ * ERRCODE_DATA_EXCEPTION without PG_TRY/PG_CATCH and substransactions,+ * but not for errors like ERRCODE_OUT_OF_MEMORY.+ */+#define PG_RETURN_ERROR(...) \+ do { \+ if (fcinfo->context && IsA(fcinfo->context, FuncCallError)) { \+ pg_prevent_errno_in_scope(); \+ \+ errstart(ERROR, TEXTDOMAIN); \+ (__VA_ARGS__); \+ castNode(FuncCallError, fcinfo->context)->error = CopyErrorData(); \+ FlushErrorState(); \+ \+ PG_RETURN_NULL(); \+ } else { \+ ereport(ERROR, (__VA_ARGS__)); \+ } \+ } while (0)+
#define TEXTDOMAIN NULL
extern bool message_level_is_interesting(int elevel);
--
2.25.1
0002-Introduce-pg_proc.proissafe-and-func_is_safe.patch (text/x-patch, 2.2K) download
From 7831b2c571784a614dd4ee4b48730187b0c0a8d1 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 31 Aug 2022 23:02:06 +0300
Subject: [PATCH 2/5] Introduce pg_proc.proissafe and func_is_safe()
---
src/backend/utils/cache/lsyscache.c | 19 +++++++++++++++++++
src/include/catalog/pg_proc.h | 3 +++
src/include/utils/lsyscache.h | 1 +
3 files changed, 23 insertions(+)
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.cindex a16a63f4957..ff3005077b2 100644--- a/src/backend/utils/cache/lsyscache.c+++ b/src/backend/utils/cache/lsyscache.c@@ -1830,6 +1830,25 @@ get_func_leakproof(Oid funcid)
return result;
}
+/*+ * func_is_safe+ * Given procedure id, return the function's proissafe flag.+ */+bool+func_is_safe(Oid funcid)+{+ HeapTuple tp;+ bool result;++ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));+ if (!HeapTupleIsValid(tp))+ elog(ERROR, "cache lookup failed for function %u", funcid);++ result = ((Form_pg_proc) GETSTRUCT(tp))->proissafe;+ ReleaseSysCache(tp);+ return result;+}+
/*
* get_func_support
*
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.hindex 76310d4cc9a..2ae8942b014 100644--- a/src/include/catalog/pg_proc.h+++ b/src/include/catalog/pg_proc.h@@ -70,6 +70,9 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
/* returns a set? */
bool proretset BKI_DEFAULT(f);
+ /* can return error info through FuncCallError instead of throwing it? */+ bool proissafe BKI_DEFAULT(f);+
/* see PROVOLATILE_ categories below */
char provolatile BKI_DEFAULT(i);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.hindex 50f02883052..c66365fdf2c 100644--- a/src/include/utils/lsyscache.h+++ b/src/include/utils/lsyscache.h@@ -130,6 +130,7 @@ extern char func_volatile(Oid funcid);
extern char func_parallel(Oid funcid);
extern char get_func_prokind(Oid funcid);
extern bool get_func_leakproof(Oid funcid);
+extern bool func_is_safe(Oid funcid);
extern RegProcedure get_func_support(Oid funcid);
extern Oid get_relname_relid(const char *relname, Oid relnamespace);
extern char *get_rel_name(Oid relid);
--
2.25.1
0003-Use-PG_RETURN_ERROR-in-float4in.patch (text/x-patch, 2.3K) download
From 4eba0bd771b85abef94125f374261d7734178657 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 31 Aug 2022 22:28:09 +0300
Subject: [PATCH 3/5] Use PG_RETURN_ERROR in float4in()
---
src/backend/utils/adt/float.c | 9 +++++----
src/include/catalog/pg_proc.dat | 2 +-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.cindex fc8f39a7a98..e3bde72b328 100644--- a/src/backend/utils/adt/float.c+++ b/src/backend/utils/adt/float.c@@ -25,6 +25,7 @@
#include "common/shortest_dec.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
+#include "nodes/execnodes.h"
#include "utils/array.h"
#include "utils/float.h"
#include "utils/fmgrprotos.h"
@@ -183,7 +184,7 @@ float4in(PG_FUNCTION_ARGS)
* strtod() on different platforms.
*/
if (*num == '\0')
- ereport(ERROR,+ PG_RETURN_ERROR(
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num)));
@@ -257,13 +258,13 @@ float4in(PG_FUNCTION_ARGS)
(val >= HUGE_VALF || val <= -HUGE_VALF)
#endif
)
- ereport(ERROR,+ PG_RETURN_ERROR(
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type real",
orig_num)));
}
else
- ereport(ERROR,+ PG_RETURN_ERROR(
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num)));
@@ -275,7 +276,7 @@ float4in(PG_FUNCTION_ARGS)
/* if there is any junk left at the end of the string, bail out */
if (*endptr != '\0')
- ereport(ERROR,+ PG_RETURN_ERROR(
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num)));
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.datindex be47583122b..b25bfa55ab3 100644--- a/src/include/catalog/pg_proc.dat+++ b/src/include/catalog/pg_proc.dat@@ -585,7 +585,7 @@
{ oid => '200', descr => 'I/O',
proname => 'float4in', prorettype => 'float4', proargtypes => 'cstring',
- prosrc => 'float4in' },+ proissafe => 't', prosrc => 'float4in' },
{ oid => '201', descr => 'I/O',
proname => 'float4out', prorettype => 'cstring', proargtypes => 'float4',
prosrc => 'float4out' },
--
2.25.1
0004-Introduce-InputFunctionCallOptError.patch (text/x-patch, 2.8K) download
From b8001f469e83df048e972dcd17120929996ba5fa Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 31 Aug 2022 22:28:44 +0300
Subject: [PATCH 4/5] Introduce InputFunctionCallOptError()
---
src/backend/utils/fmgr/fmgr.c | 38 +++++++++++++++++++++++++++++++++--
src/include/fmgr.h | 3 +++
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.cindex a9dd068095b..fbea0df61df 100644--- a/src/backend/utils/fmgr/fmgr.c+++ b/src/backend/utils/fmgr/fmgr.c@@ -1511,11 +1511,14 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
* function anyway if it's not strict. So this is almost but not quite
* the same as FunctionCall3.
*/
-Datum-InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)+static inline Datum+InputFunctionCallInternal(FmgrInfo *flinfo, char *str,+ Oid typioparam, int32 typmod,+ ErrorData **edata)
{
LOCAL_FCINFO(fcinfo, 3);
Datum result;
+ FuncCallError *fcerror;
if (str == NULL && flinfo->fn_strict)
return (Datum) 0; /* just return null result */
@@ -1529,8 +1532,22 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
fcinfo->args[2].value = Int32GetDatum(typmod);
fcinfo->args[2].isnull = false;
+ if (edata)+ {+ fcerror = makeNode(FuncCallError);+ fcinfo->context = (Node *) fcerror;+ }+
result = FunctionCallInvoke(fcinfo);
+ if (edata)+ {+ *edata = fcerror->error;+ pfree(fcerror);+ if (*edata)+ return (Datum) 0;+ }+
/* Should get null result if and only if str is NULL */
if (str == NULL)
{
@@ -1548,6 +1565,23 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
return result;
}
+Datum+InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)+{+ return InputFunctionCallInternal(flinfo, str, typioparam, typmod, NULL);+}++Datum+InputFunctionCallOptError(FmgrInfo *flinfo, char *str, Oid typioparam,+ int32 typmod, ErrorData **edata)+{+ if (edata)+ return InputFunctionCallInternal(flinfo, str, typioparam, typmod, edata);+ else+ return InputFunctionCall(flinfo, str, typioparam, typmod);+}++
/*
* Call a previously-looked-up datatype output function.
*
diff --git a/src/include/fmgr.h b/src/include/fmgr.hindex 380a82b9de3..8f18f2408e1 100644--- a/src/include/fmgr.h+++ b/src/include/fmgr.h@@ -711,6 +711,9 @@ extern Datum OidReceiveFunctionCall(Oid functionId, fmStringInfo buf,
extern bytea *SendFunctionCall(FmgrInfo *flinfo, Datum val);
extern bytea *OidSendFunctionCall(Oid functionId, Datum val);
+extern Datum InputFunctionCallOptError(FmgrInfo *flinfo, char *str,+ Oid typioparam, int32 typmod,+ ErrorData **edata);
/*
* Routines in fmgr.c
--
2.25.1
0005-Introduce-NULL_ON_ERROR-option-for-COPY-FROM.patch (text/x-patch, 7.2K) download
From 1fc1b4231b079078c303be75864c4ef71d0742a1 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 31 Aug 2022 22:29:47 +0300
Subject: [PATCH 5/5] Introduce NULL_ON_ERROR option for COPY FROM
---
src/backend/commands/copy.c | 20 +++++++++++++++++
src/backend/commands/copyfrom.c | 33 ++++++++++++++++++++++++++++
src/backend/commands/copyfromparse.c | 21 +++++++++++++-----
src/include/commands/copy.h | 2 ++
src/test/regress/expected/copy.out | 15 +++++++++++++
src/test/regress/sql/copy.sql | 13 +++++++++++
6 files changed, 99 insertions(+), 5 deletions(-)
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.cindex 49924e476af..ce7e875f655 100644--- a/src/backend/commands/copy.c+++ b/src/backend/commands/copy.c@@ -551,6 +551,19 @@ ProcessCopyOptions(ParseState *pstate,
defel->defname),
parser_errposition(pstate, defel->location)));
}
+ else if (strcmp(defel->defname, "null_on_error") == 0)+ {+ if (opts_out->null_on_error)+ errorConflictingDefElem(defel, pstate);+ if (defel->arg && IsA(defel->arg, List))+ opts_out->null_on_error = castNode(List, defel->arg);+ else+ ereport(ERROR,+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),+ errmsg("argument to option \"%s\" must be a list of column names",+ defel->defname),+ parser_errposition(pstate, defel->location)));+ }
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -701,6 +714,13 @@ ProcessCopyOptions(ParseState *pstate,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("CSV quote character must not appear in the NULL specification")));
++ /* Check null_on_error */+ if (opts_out->null_on_error != NIL && !is_from)+ ereport(ERROR,+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),+ errmsg("COPY null on error only available using COPY FROM")));+
}
/*
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.cindex e8bb168aea8..99b39d8d7c2 100644--- a/src/backend/commands/copyfrom.c+++ b/src/backend/commands/copyfrom.c@@ -47,6 +47,7 @@
#include "rewrite/rewriteHandler.h"
#include "storage/fd.h"
#include "tcop/tcopprot.h"
+#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/portal.h"
@@ -1316,6 +1317,29 @@ BeginCopyFrom(ParseState *pstate,
}
}
+ /* Convert NULL_ON_ERROR name list to per-column flags, check validity */+ cstate->opts.null_on_error_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));+ if (cstate->opts.null_on_error)+ {+ List *attnums;+ ListCell *cur;++ attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.null_on_error);++ foreach(cur, attnums)+ {+ int attnum = lfirst_int(cur);+ Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);++ if (!list_member_int(cstate->attnumlist, attnum))+ ereport(ERROR,+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),+ errmsg("NULL_ON_ERROR column \"%s\" not referenced by COPY",+ NameStr(attr->attname))));+ cstate->opts.null_on_error_flags[attnum - 1] = true;+ }+ }+
/* Use client encoding when ENCODING option is not specified. */
if (cstate->opts.file_encoding < 0)
cstate->file_encoding = pg_get_client_encoding();
@@ -1417,6 +1441,15 @@ BeginCopyFrom(ParseState *pstate,
&in_func_oid, &typioparams[attnum - 1]);
fmgr_info(in_func_oid, &in_functions[attnum - 1]);
+ /* check whether input function supports returning errors */+ if (cstate->opts.null_on_error_flags[attnum - 1] &&+ !func_is_safe(in_func_oid))+ ereport(ERROR,+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),+ errmsg("input function for datatype \"%s\" does not support error handling",+ format_type_be(att->atttypid))));++
/* Get default info if needed */
if (!list_member_int(cstate->attnumlist, attnum) && !att->attgenerated)
{
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.cindex 097414ef12d..04a36de444c 100644--- a/src/backend/commands/copyfromparse.c+++ b/src/backend/commands/copyfromparse.c@@ -897,6 +897,8 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
int attnum = lfirst_int(cur);
int m = attnum - 1;
Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+ ErrorData *edata = NULL;+ ErrorData **p_edata;
if (fieldno >= fldct)
ereport(ERROR,
@@ -938,11 +940,20 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
cstate->cur_attname = NameStr(att->attname);
cstate->cur_attval = string;
- values[m] = InputFunctionCall(&in_functions[m],- string,- typioparams[m],- att->atttypmod);- if (string != NULL)++ p_edata = cstate->opts.null_on_error_flags[m] ? &edata : NULL;++ values[m] = InputFunctionCallOptError(&in_functions[m],+ string,+ typioparams[m],+ att->atttypmod,+ p_edata);+ if (edata)+ {+ FreeErrorData(edata);+ nulls[m] = true;+ }+ else if (string != NULL)
nulls[m] = false;
cstate->cur_attname = NULL;
cstate->cur_attval = NULL;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.hindex cb0096aeb67..359fb4cc9e0 100644--- a/src/include/commands/copy.h+++ b/src/include/commands/copy.h@@ -59,6 +59,8 @@ typedef struct CopyFormatOptions
bool *force_null_flags; /* per-column CSV FN flags */
bool convert_selectively; /* do selective binary conversion? */
List *convert_select; /* list of column names (can be NIL) */
+ List *null_on_error; /* list of column names */+ bool *null_on_error_flags; /* per-column NOE flags */
} CopyFormatOptions;
/* These are private in commands/copy[from|to].c */
diff --git a/src/test/regress/expected/copy.out b/src/test/regress/expected/copy.outindex 3fad1c52d1f..82839d2f67a 100644--- a/src/test/regress/expected/copy.out+++ b/src/test/regress/expected/copy.out@@ -240,3 +240,18 @@ SELECT * FROM header_copytest ORDER BY a;
(5 rows)
drop table header_copytest;
+create table null_on_error_copytest(i int, f float4);+copy null_on_error_copytest from stdin with (null_on_error (i, f));+ERROR: input function for datatype "integer" does not support error handling+copy null_on_error_copytest from stdin with (null_on_error (f));+copy null_on_error_copytest from stdin with (null_on_error (f));+ERROR: invalid input syntax for type integer: "err"+CONTEXT: COPY null_on_error_copytest, line 2, column i: "err"+select * from null_on_error_copytest;+ i | f +---+-----+ 1 | 2.3+ 2 | +(2 rows)++drop table null_on_error_copytest;diff --git a/src/test/regress/sql/copy.sql b/src/test/regress/sql/copy.sqlindex 285022e07c6..914e29d5ba1 100644--- a/src/test/regress/sql/copy.sql+++ b/src/test/regress/sql/copy.sql@@ -268,3 +268,16 @@ a c b
SELECT * FROM header_copytest ORDER BY a;
drop table header_copytest;
++create table null_on_error_copytest(i int, f float4);+copy null_on_error_copytest from stdin with (null_on_error (i, f));+copy null_on_error_copytest from stdin with (null_on_error (f));+1 2.3+2 err+\.+copy null_on_error_copytest from stdin with (null_on_error (f));+1 2.3+err 4.5+\.+select * from null_on_error_copytest;+drop table null_on_error_copytest;--
2.25.1
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: n.gluhov@postgrespro.ru, tgl@sss.pgh.pa.us, robertmhaas@gmail.com, andres@anarazel.de, jkatz@postgresql.org, andrew@dunslane.net, amitlangote09@gmail.com, alvherre@alvh.no-ip.org, pgsql-hackers@lists.postgresql.org, michael@paquier.xyz, john.naylor@enterprisedb.com
Subject: Re: SQL/JSON features for v15
In-Reply-To: <379e5365-9670-e0de-ee08-57ba61cbc976@postgrespro.ru>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox