public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v45 3/3] Replace assuming a composite object on a scalar
3+ messages / 3 participants
[nested] [flat]
* [PATCH v45 3/3] Replace assuming a composite object on a scalar
@ 2021-01-07 08:04 Dmitrii Dolgov <[email protected]>
0 siblings, 0 replies; 3+ messages in thread
From: Dmitrii Dolgov @ 2021-01-07 08:04 UTC (permalink / raw)
For jsonb subscripting assignment it could happen that the provided path
assumes an object or an array at some level, but the source jsonb has a
scalar value there. Originally the update operation will be skipped and
no message will be shown that nothing happened. Return an error to
indicate such situations.
---
doc/src/sgml/json.sgml | 22 ++++++++++++++++++++--
src/backend/utils/adt/jsonfuncs.c | 11 +++++++++++
src/test/regress/expected/jsonb.out | 12 ++++++++++++
src/test/regress/sql/jsonb.sql | 8 ++++++++
4 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index 9af015d222..924762e128 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -612,8 +612,23 @@ SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qu
<literal>path</literal> argument in <literal>jsonb_set</literal> function,
e.g. in case of arrays it is a 0-based operation or that negative integers
that appear in <literal>path</literal> count from the end of JSON arrays.
- The result of subscripting expressions is always jsonb data type. An
- example of subscripting syntax:
+ The result of subscripting expressions is always jsonb data type.
+
+ <para>
+ <command>UPDATE</command> statements may use subscripting in the
+ <literal>SET</literal> clause to modify <type>jsonb</type> values. Every
+ affected value must conform to the path defined by the subscript(s). If the
+ path contradicts structure of modified <type>jsonb</type> for any individual
+ value (e.g. path <literal>val['a']['b']['c']</literal> assumes keys
+ <literal>'a'</literal> and <literal>'b'</literal> have object values
+ assigned to them, but if <literal>val['a']</literal> or
+ <literal>val['b']</literal> is null, a string, or a number, then the path
+ contradicts with the existing structure), an error is raised even if other
+ values do conform.
+ </para>
+ <para>
+
+ An example of subscripting syntax:
<programlisting>
-- Extract value by key
SELECT ('{"a": 1}'::jsonb)['a'];
@@ -628,6 +643,9 @@ SELECT ('[1, "2", null]'::jsonb)[1];
-- needs to be of jsonb type as well
UPDATE table_name SET jsonb_field['key'] = '1';
+-- This will raise an error if jsonb_field is {"a": 1}
+UPDATE table_name SET jsonb_field['a']['b']['c'] = '1';
+
-- Select records using where clause with subscripting. Since the result of
-- subscripting is jsonb and we basically want to compare two jsonb objects, we
-- need to put the value in double quotes to be able to convert it to jsonb.
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index f14f6c3191..ebc0b06f5b 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -4943,6 +4943,17 @@ setPath(JsonbIterator **it, Datum *path_elems,
break;
case WJB_ELEM:
case WJB_VALUE:
+ /*
+ * If instructed complain about attempts to replace whithin a
+ * scalar value.
+ */
+ if ((op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot replace existing key"),
+ errdetail("The path assumes key is a composite object, "
+ "but it is a scalar value.")));
+
res = pushJsonbValue(st, r, &v);
break;
default:
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index b7c268b53f..0df808c36d 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -5134,6 +5134,18 @@ select * from test_jsonb_subscript;
1 | {"a": [null, {"c": [null, null, 1]}]}
(1 row)
+-- trying replace assuming a composite object, but it's a scalar
+delete from test_jsonb_subscript;
+insert into test_jsonb_subscript values (1, '{"a": 1}');
+update test_jsonb_subscript set test_json['a']['b']['c'] = '1';
+ERROR: cannot replace existing key
+DETAIL: The path assumes key is a composite object, but it is a scalar value.
+update test_jsonb_subscript set test_json['a'][0]['c'] = '1';
+ERROR: cannot replace existing key
+DETAIL: The path assumes key is a composite object, but it is a scalar value.
+update test_jsonb_subscript set test_json['a'][0][0] = '1';
+ERROR: cannot replace existing key
+DETAIL: The path assumes key is a composite object, but it is a scalar value.
-- jsonb to tsvector
select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
to_tsvector
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 0320db0ea4..c62a2f9aec 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -1371,6 +1371,14 @@ insert into test_jsonb_subscript values (1, '{"a": []}');
update test_jsonb_subscript set test_json['a'][1]['c'][2] = '1';
select * from test_jsonb_subscript;
+-- trying replace assuming a composite object, but it's a scalar
+
+delete from test_jsonb_subscript;
+insert into test_jsonb_subscript values (1, '{"a": 1}');
+update test_jsonb_subscript set test_json['a']['b']['c'] = '1';
+update test_jsonb_subscript set test_json['a'][0]['c'] = '1';
+update test_jsonb_subscript set test_json['a'][0][0] = '1';
+
-- jsonb to tsvector
select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
--
2.21.0
--2v7pubbjx3p2om6u--
^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: Extension Enhancement: Buffer Invalidation in pg_buffercache
@ 2023-07-04 09:00 jian he <[email protected]>
0 siblings, 1 reply; 3+ messages in thread
From: jian he @ 2023-07-04 09:00 UTC (permalink / raw)
To: Japin Li <[email protected]>; +Cc: Palak Chaturvedi <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers; [email protected]
the following will also crash. no idea why.
begin;
select count(*) from onek;
select relpages from pg_class where relname = 'onek'; --queryA
SELECT count(*) FROM pg_buffercache WHERE relfilenode =
pg_relation_filenode('onek'::regclass); --queryB
insert into onek values(default);
select count(pg_buffercache_invalidate(bufferid)) from
pg_buffercache where relfilenode =
pg_relation_filenode('onek'::regclass);
---------------------------------
queryA returns 35, queryB returns 37.
----------------------------------
crash info:
test_dev=*# insert into onek values(default);
INSERT 0 1
test_dev=*# select count(pg_buffercache_invalidate(bufferid)) from
pg_buffercache where relfilenode =
pg_relation_filenode('onek'::regclass);
TRAP: failed Assert("resarr->nitems < resarr->maxitems"), File:
"../../Desktop/pg_sources/main/postgres/src/backend/utils/resowner/resowner.c",
Line: 275, PID: 1533312
postgres: jian test_dev [local]
SELECT(ExceptionalCondition+0xa1)[0x55fc8f8d14e1]
postgres: jian test_dev [local] SELECT(+0x9e7ab3)[0x55fc8f915ab3]
postgres: jian test_dev [local]
SELECT(ResourceOwnerRememberBuffer+0x1d)[0x55fc8f91696d]
postgres: jian test_dev [local] SELECT(+0x78ab17)[0x55fc8f6b8b17]
postgres: jian test_dev [local]
SELECT(TryInvalidateBuffer+0x6d)[0x55fc8f6c507d]
/home/jian/postgres/pg16_test/lib/pg_buffercache.so(pg_buffercache_invalidate+0x3d)[0x7f2361837abd]
postgres: jian test_dev [local] SELECT(+0x57eebc)[0x55fc8f4acebc]
postgres: jian test_dev [local]
SELECT(ExecInterpExprStillValid+0x3c)[0x55fc8f4a6e2c]
postgres: jian test_dev [local] SELECT(+0x5a0f16)[0x55fc8f4cef16]
postgres: jian test_dev [local] SELECT(+0x5a3588)[0x55fc8f4d1588]
postgres: jian test_dev [local] SELECT(+0x58f747)[0x55fc8f4bd747]
postgres: jian test_dev [local]
SELECT(standard_ExecutorRun+0x1f0)[0x55fc8f4b29f0]
postgres: jian test_dev [local] SELECT(ExecutorRun+0x46)[0x55fc8f4b2d16]
postgres: jian test_dev [local] SELECT(+0x7eb3b0)[0x55fc8f7193b0]
postgres: jian test_dev [local] SELECT(PortalRun+0x1eb)[0x55fc8f71b7ab]
postgres: jian test_dev [local] SELECT(+0x7e8cf4)[0x55fc8f716cf4]
postgres: jian test_dev [local] SELECT(PostgresMain+0x134f)[0x55fc8f71869f]
postgres: jian test_dev [local] SELECT(+0x70f80c)[0x55fc8f63d80c]
postgres: jian test_dev [local]
SELECT(PostmasterMain+0x1758)[0x55fc8f63f278]
postgres: jian test_dev [local] SELECT(main+0x27e)[0x55fc8f27067e]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7f2361629d90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7f2361629e40]
postgres: jian test_dev [local] SELECT(_start+0x25)[0x55fc8f272bb5]
2023-07-04 16:56:13.088 CST [1532822] LOG: server process (PID 1533312)
was terminated by signal 6: Aborted
2023-07-04 16:56:13.088 CST [1532822] DETAIL: Failed process was running:
select count(pg_buffercache_invalidate(bufferid)) from
pg_buffercache where relfilenode =
pg_relation_filenode('onek'::regclass);
2023-07-04 16:56:13.088 CST [1532822] LOG: terminating any other active
server processes
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: 2023-07-04
16:56:13.091 CST [1533381] FATAL: the database system is in recovery mode
Failed.
The connection to the server was lost. Attempting reset: Failed.
^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: Extension Enhancement: Buffer Invalidation in pg_buffercache
@ 2023-07-04 09:45 Japin Li <[email protected]>
parent: jian he <[email protected]>
0 siblings, 0 replies; 3+ messages in thread
From: Japin Li @ 2023-07-04 09:45 UTC (permalink / raw)
To: jian he <[email protected]>; +Cc: Palak Chaturvedi <[email protected]>; Thomas Munro <[email protected]>; pgsql-hackers; [email protected]
On Tue, 04 Jul 2023 at 17:00, jian he <[email protected]> wrote:
> the following will also crash. no idea why.
> begin;
> select count(*) from onek;
> select relpages from pg_class where relname = 'onek'; --queryA
>
> SELECT count(*) FROM pg_buffercache WHERE relfilenode =
> pg_relation_filenode('onek'::regclass); --queryB
>
> insert into onek values(default);
>
> select count(pg_buffercache_invalidate(bufferid)) from
> pg_buffercache where relfilenode =
> pg_relation_filenode('onek'::regclass);
>
> ---------------------------------
> queryA returns 35, queryB returns 37.
> ----------------------------------
> crash info:
> test_dev=*# insert into onek values(default);
> INSERT 0 1
> test_dev=*# select count(pg_buffercache_invalidate(bufferid)) from
> pg_buffercache where relfilenode =
> pg_relation_filenode('onek'::regclass);
> TRAP: failed Assert("resarr->nitems < resarr->maxitems"), File:
> "../../Desktop/pg_sources/main/postgres/src/backend/utils/resowner/resowner.c",
> Line: 275, PID: 1533312
According to the comments of ResourceArrayAdd(), the caller must have previously
done ResourceArrayEnlarge(). I tried to call ResourceOwnerEnlargeBuffers() before
PinBuffer_Locked(), so it can avoid this crash.
if ((buf_state & BM_DIRTY) == BM_DIRTY)
{
+ /* make sure we can handle the pin */
+ ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
+
/*
* Try once to flush the dirty buffer.
*/
PinBuffer_Locked(bufHdr);
--
Regrads,
Japin Li.
^ permalink raw reply [nested|flat] 3+ messages in thread
end of thread, other threads:[~2023-07-04 09:45 UTC | newest]
Thread overview: 3+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-01-07 08:04 [PATCH v45 3/3] Replace assuming a composite object on a scalar Dmitrii Dolgov <[email protected]>
2023-07-04 09:00 Re: Extension Enhancement: Buffer Invalidation in pg_buffercache jian he <[email protected]>
2023-07-04 09:45 ` Re: Extension Enhancement: Buffer Invalidation in pg_buffercache Japin Li <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox