Skip to content

Commit 1edb3b4

Browse files
committed
Adjust populate_record_field() to handle errors softly
This adds a Node *escontext parameter to it and a bunch of functions downstream to it, replacing any ereport()s in that path by either errsave() or ereturn() as appropriate. This also adds code to those functions where necessary to return early upon encountering a soft error. The changes here are mainly intended to suppress errors in the functions of jsonfuncs.c. Functions in any external modules, such as arrayfuncs.c, that those functions may in turn call are not changed here based on the assumption that the various checks in jsonfuncs.c functions should ensure that only values that are structurally valid get passed to the functions in those external modules. An exception is made for domain_check() to allow handling domain constraint violation errors softly. For testing, this adds a function jsonb_populate_record_valid(), which returns true if jsonb_populate_record() would finish without causing an error for the provided JSON object, false otherwise. Note that jsonb_populate_record() internally calls populate_record(), which in turn uses populate_record_field(). Extracted from a much larger patch to add SQL/JSON query functions. Author: Nikita Glukhov <n.gluhov@postgrespro.ru> Author: Teodor Sigaev <teodor@sigaev.ru> Author: Oleg Bartunov <obartunov@gmail.com> Author: Alexander Korotkov <aekorotkov@gmail.com> Author: Andrew Dunstan <andrew@dunslane.net> Author: Amit Langote <amitlangote09@gmail.com> Reviewers have included (in no particular order) Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zihong Yu, Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby, Álvaro Herrera, Jian He, Peter Eisentraut Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru Discussion: https://postgr.es/m/20220616233130.rparivafipt6doj3@alap3.anarazel.de Discussion: https://postgr.es/m/abd9b83b-aa66-f230-3d6d-734817f0995d%40postgresql.org Discussion: https://postgr.es/m/CA+HiwqHROpf9e644D8BRqYvaAPmgBZVup-xKMDPk-nd4EpgzHw@mail.gmail.com Discussion: https://postgr.es/m/CA+HiwqE4XTdfb1nW=Ojoy_tQSRhYt-q_kb6i5d4xcKyrLC1Nbg@mail.gmail.com
1 parent aaaf944 commit 1edb3b4

File tree

7 files changed

+521
-87
lines changed

7 files changed

+521
-87
lines changed

doc/src/sgml/func.sgml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16727,6 +16727,58 @@ array w/o UK? | t
1672716727
</para></entry>
1672816728
</row>
1672916729

16730+
<row>
16731+
<entry role="func_table_entry"><para role="func_signature">
16732+
<indexterm>
16733+
<primary>jsonb_populate_record_valid</primary>
16734+
</indexterm>
16735+
<function>jsonb_populate_record_valid</function> ( <parameter>base</parameter> <type>anyelement</type>, <parameter>from_json</parameter> <type>json</type> )
16736+
<returnvalue>boolean</returnvalue>
16737+
</para>
16738+
<para>
16739+
Function for testing <function>jsonb_populate_record</function>. Returns
16740+
<literal>true</literal> if the input <function>jsonb_populate_record</function>
16741+
would finish without an error for the given input JSON object; that is, it's
16742+
valid input, <literal>false</literal> otherwise.
16743+
</para>
16744+
<para>
16745+
<literal>create type jsb_char2 as (a char(2));</literal>
16746+
</para>
16747+
<para>
16748+
<literal>select jsonb_populate_record_valid(NULL::jsb_char2, '{"a": "aaa"}');</literal>
16749+
<returnvalue></returnvalue>
16750+
<programlisting>
16751+
jsonb_populate_record_valid
16752+
-----------------------------
16753+
f
16754+
(1 row)
16755+
</programlisting>
16756+
16757+
<literal>select * from jsonb_populate_record(NULL::jsb_char2, '{"a": "aaa"}') q;</literal>
16758+
<returnvalue></returnvalue>
16759+
<programlisting>
16760+
ERROR: value too long for type character(2)
16761+
</programlisting>
16762+
<literal>select jsonb_populate_record_valid(NULL::jsb_char2, '{"a": "aa"}');</literal>
16763+
<returnvalue></returnvalue>
16764+
<programlisting>
16765+
jsonb_populate_record_valid
16766+
-----------------------------
16767+
t
16768+
(1 row)
16769+
</programlisting>
16770+
16771+
<literal>select * from jsonb_populate_record(NULL::jsb_char2, '{"a": "aa"}') q;</literal>
16772+
<returnvalue></returnvalue>
16773+
<programlisting>
16774+
a
16775+
----
16776+
aa
16777+
(1 row)
16778+
</programlisting>
16779+
</para></entry>
16780+
</row>
16781+
1673016782
<row>
1673116783
<entry role="func_table_entry"><para role="func_signature">
1673216784
<indexterm>

src/backend/utils/adt/domains.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
#include "utils/syscache.h"
4141
#include "utils/typcache.h"
4242

43+
static bool domain_check_internal(Datum value, bool isnull, Oid domainType,
44+
void **extra, MemoryContext mcxt,
45+
Node *escontext);
4346

4447
/*
4548
* structure to cache state across multiple calls
@@ -342,6 +345,32 @@ domain_recv(PG_FUNCTION_ARGS)
342345
void
343346
domain_check(Datum value, bool isnull, Oid domainType,
344347
void **extra, MemoryContext mcxt)
348+
{
349+
(void) domain_check_internal(value, isnull, domainType, extra, mcxt,
350+
NULL);
351+
}
352+
353+
/* Error-safe variant of domain_check(). */
354+
bool
355+
domain_check_safe(Datum value, bool isnull, Oid domainType,
356+
void **extra, MemoryContext mcxt,
357+
Node *escontext)
358+
{
359+
return domain_check_internal(value, isnull, domainType, extra, mcxt,
360+
escontext);
361+
}
362+
363+
/*
364+
* domain_check_internal
365+
* Workhorse for domain_check() and domain_check_safe()
366+
*
367+
* Returns false if an error occurred in domain_check_input() and 'escontext'
368+
* points to an ErrorSaveContext, true otherwise.
369+
*/
370+
static bool
371+
domain_check_internal(Datum value, bool isnull, Oid domainType,
372+
void **extra, MemoryContext mcxt,
373+
Node *escontext)
345374
{
346375
DomainIOData *my_extra = NULL;
347376

@@ -365,7 +394,9 @@ domain_check(Datum value, bool isnull, Oid domainType,
365394
/*
366395
* Do the necessary checks to ensure it's a valid domain value.
367396
*/
368-
domain_check_input(value, isnull, my_extra, NULL);
397+
domain_check_input(value, isnull, my_extra, escontext);
398+
399+
return !SOFT_ERROR_OCCURRED(escontext);
369400
}
370401

371402
/*

0 commit comments

Comments
 (0)