Skip to content

Commit 95d6f4d

Browse files
committed
implement ELEMENT OF jsonb AS e WITH INDEX AS i SATISFIES
1 parent 1e81b00 commit 95d6f4d

File tree

4 files changed

+72
-11
lines changed

4 files changed

+72
-11
lines changed

src/backend/parser/gram.y

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
177177
bool *no_inherit, core_yyscan_t yyscanner);
178178
static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
179179
static SelectStmt * makeElementSubselect(int any_or_each, int kind, bool recursive, Node *of,
180-
const char *aliasname, Node *clause, int location);
180+
const char *aliasname, const char *indexname,
181+
Node *clause, int location);
181182

182183
%}
183184

@@ -292,6 +293,7 @@ static SelectStmt * makeElementSubselect(int any_or_each, int kind, bool recursi
292293
opt_grant_grant_option opt_grant_admin_option
293294
opt_nowait opt_if_exists opt_with_data
294295
opt_anywhere
296+
%type <str> opt_with_index
295297
%type <ival> opt_nowait_or_skip
296298

297299
%type <list> OptRoleList AlterOptRoleList
@@ -12060,6 +12062,18 @@ c_expr: columnref { $$ = $1; }
1206012062
g->location = @1;
1206112063
$$ = (Node *)g;
1206212064
}
12065+
| any_or_each ELEMENT opt_anywhere OF b_expr AS ColId opt_with_index SATISFIES '(' a_expr ')'
12066+
{
12067+
SubLink *n = makeNode(SubLink);
12068+
12069+
n->subLinkType = EXPR_SUBLINK;
12070+
n->subLinkId = 0;
12071+
n->testexpr = NULL;
12072+
n->operName = NIL;
12073+
n->subselect = (Node*)makeElementSubselect($1, ELEMENT, $3, $5, $7, $8, $11, @1);
12074+
n->location = @1;
12075+
$$ = (Node *)n;
12076+
}
1206312077
| any_or_each any_or_each_kind opt_anywhere OF b_expr AS ColId SATISFIES '(' a_expr ')'
1206412078
{
1206512079
SubLink *n = makeNode(SubLink);
@@ -12068,7 +12082,7 @@ c_expr: columnref { $$ = $1; }
1206812082
n->subLinkId = 0;
1206912083
n->testexpr = NULL;
1207012084
n->operName = NIL;
12071-
n->subselect = (Node*)makeElementSubselect($1, $2, $3, $5, $7, $10, @1);
12085+
n->subselect = (Node*)makeElementSubselect($1, $2, $3, $5, $7, NULL, $10, @1);
1207212086
n->location = @1;
1207312087
$$ = (Node *)n;
1207412088
}
@@ -12080,11 +12094,15 @@ any_or_each:
1208012094
;
1208112095

1208212096
any_or_each_kind:
12083-
ELEMENT { $$ = ELEMENT; }
12084-
| KEY { $$ = KEY; }
12097+
KEY { $$ = KEY; }
1208512098
| VALUE_P { $$ = VALUE_P; }
1208612099
;
1208712100

12101+
opt_with_index:
12102+
WITH INDEX AS ColId { $$ = $4; }
12103+
| /* empty */ { $$ = NULL; }
12104+
;
12105+
1208812106
opt_anywhere:
1208912107
ANYWHERE { $$ = true; }
1209012108
| /* empty */ { $$ = false; }
@@ -14866,7 +14884,8 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
1486614884

1486714885
static SelectStmt *
1486814886
makeElementSubselect(int any_or_each, int kind, bool recursive, Node *of,
14869-
const char *aliasname, Node *clause, int location)
14887+
const char *aliasname, const char *indexname,
14888+
Node *clause, int location)
1487014889
{
1487114890
ResTarget *target = makeNode(ResTarget);
1487214891
FuncCall *unnest_call, *agg_call, *count_call;
@@ -14930,7 +14949,7 @@ makeElementSubselect(int any_or_each, int kind, bool recursive, Node *of,
1493014949
switch(kind)
1493114950
{
1493214951
case ELEMENT:
14933-
unnest_name = "unnest_element";
14952+
unnest_name = indexname ? "unnest_element_index" : "unnest_element";
1493414953
break;
1493514954
case KEY:
1493614955
unnest_name = "unnest_key";
@@ -14948,6 +14967,8 @@ makeElementSubselect(int any_or_each, int kind, bool recursive, Node *of,
1494814967

1494914968
table_ref->functions = list_make1(list_make2(unnest_call, NIL));
1495014969
table_ref->alias = makeAlias(aliasname, NIL);
14970+
if (indexname)
14971+
table_ref->alias->colnames = list_make2(makeString(pstrdup(aliasname)), makeString(pstrdup(indexname)));
1495114972
subselect->fromClause = list_make1(table_ref);
1495214973

1495314974
return subselect;

src/backend/utils/adt/jsonfuncs.c

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3900,14 +3900,16 @@ typedef struct UnnestState
39003900
JsonbIterator *it;
39013901
bool skipNested;
39023902
JsonbIteratorToken type;
3903+
int32 counter;
3904+
TupleDesc tupdesc;
39033905
}
39043906
UnnestState;
39053907

39063908
static void finiUnnest(UnnestState *state);
39073909

39083910
static void
39093911
initUnnest(FuncCallContext *funcctx, Datum jsonb, bool recursive,
3910-
JsonbIteratorToken type)
3912+
JsonbIteratorToken type, FunctionCallInfo fcinfo)
39113913
{
39123914
MemoryContext oldcontext;
39133915
UnnestState *state;
@@ -3932,6 +3934,10 @@ initUnnest(FuncCallContext *funcctx, Datum jsonb, bool recursive,
39323934
Assert(r == WJB_DONE);
39333935
}
39343936

3937+
if (r != WJB_DONE && fcinfo &&
3938+
get_call_result_type(fcinfo, NULL, &state->tupdesc) != TYPEFUNC_COMPOSITE)
3939+
elog(ERROR, "return type must be a row type");
3940+
39353941
MemoryContextSwitchTo(oldcontext);
39363942

39373943
if (r == WJB_DONE)
@@ -3940,6 +3946,7 @@ initUnnest(FuncCallContext *funcctx, Datum jsonb, bool recursive,
39403946
state = NULL;
39413947
}
39423948

3949+
39433950
funcctx->user_fctx = (void *) state;
39443951
}
39453952

@@ -3963,6 +3970,8 @@ nextUnnest(UnnestState *state)
39633970

39643971
MemoryContextSwitchTo(oldcontext);
39653972

3973+
state->counter ++;
3974+
39663975
return (r == state->type) ? JsonbValueToJsonb(&v) : NULL;
39673976
}
39683977

@@ -4008,7 +4017,7 @@ jsonb_unnest_element(PG_FUNCTION_ARGS)
40084017

40094018
if (SRF_IS_FIRSTCALL())
40104019
initUnnest(SRF_FIRSTCALL_INIT(), PG_GETARG_DATUM(0),
4011-
PG_GETARG_BOOL(1), WJB_ELEM);
4020+
PG_GETARG_BOOL(1), WJB_ELEM, NULL);
40124021

40134022
funcctx = SRF_PERCALL_SETUP();
40144023
state = funcctx->user_fctx;
@@ -4022,6 +4031,34 @@ jsonb_unnest_element(PG_FUNCTION_ARGS)
40224031
SRF_RETURN_NEXT(funcctx, JsonbGetDatum(r));
40234032
}
40244033

4034+
Datum
4035+
jsonb_unnest_element_index(PG_FUNCTION_ARGS)
4036+
{
4037+
FuncCallContext *funcctx;
4038+
UnnestState *state;
4039+
Jsonb *r;
4040+
Datum vals[2];
4041+
bool nulls[2] = {false, false};
4042+
4043+
if (SRF_IS_FIRSTCALL())
4044+
initUnnest(SRF_FIRSTCALL_INIT(), PG_GETARG_DATUM(0),
4045+
PG_GETARG_BOOL(1), WJB_ELEM, fcinfo);
4046+
4047+
funcctx = SRF_PERCALL_SETUP();
4048+
state = funcctx->user_fctx;
4049+
4050+
if (state == NULL || (r = nextUnnest(state)) == NULL)
4051+
{
4052+
finiUnnest(state);
4053+
SRF_RETURN_DONE(funcctx);
4054+
}
4055+
4056+
vals[0] = JsonbGetDatum(r);
4057+
vals[1] = Int32GetDatum(state->counter - 1);
4058+
4059+
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(heap_form_tuple(state->tupdesc, vals, nulls)));
4060+
}
4061+
40254062
Datum
40264063
jsonb_unnest_value(PG_FUNCTION_ARGS)
40274064
{
@@ -4031,7 +4068,7 @@ jsonb_unnest_value(PG_FUNCTION_ARGS)
40314068

40324069
if (SRF_IS_FIRSTCALL())
40334070
initUnnest(SRF_FIRSTCALL_INIT(), PG_GETARG_DATUM(0),
4034-
PG_GETARG_BOOL(1), WJB_VALUE);
4071+
PG_GETARG_BOOL(1), WJB_VALUE, NULL);
40354072

40364073
funcctx = SRF_PERCALL_SETUP();
40374074
state = funcctx->user_fctx;
@@ -4050,11 +4087,11 @@ jsonb_unnest_key(PG_FUNCTION_ARGS)
40504087
{
40514088
FuncCallContext *funcctx;
40524089
UnnestState *state;
4053-
Jsonb *r;
4090+
text *r;
40544091

40554092
if (SRF_IS_FIRSTCALL())
40564093
initUnnest(SRF_FIRSTCALL_INIT(), PG_GETARG_DATUM(0),
4057-
PG_GETARG_BOOL(1), WJB_KEY);
4094+
PG_GETARG_BOOL(1), WJB_KEY, NULL);
40584095

40594096
funcctx = SRF_PERCALL_SETUP();
40604097
state = funcctx->user_fctx;

src/include/catalog/pg_proc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4876,6 +4876,8 @@ DATA(insert OID = 3306 ( jsonb_pretty PGNSP PGUID 12 1 0 0 0 f f f f t f i 1
48764876
DESCR("Indented text from jsonb");
48774877
DATA(insert OID = 7645 ( unnest_element PGNSP PGUID 12 1 100 0 0 f f f f t t i 2 0 3802 "3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_unnest_element _null_ _null_ _null_ ));
48784878
DESCR("expand elements from jsonb");
4879+
DATA(insert OID = 7652 ( unnest_element_index PGNSP PGUID 12 1 100 0 0 f f f f t t i 2 0 2249 "3802 16" "{3802,16,3802,23}" "{i,i,o,o}" "{jsonb_in,recursive,element,index}" _null_ _null_ jsonb_unnest_element_index _null_ _null_ _null_ ));
4880+
DESCR("expand elements from jsonb");
48794881
DATA(insert OID = 7646 ( unnest_value PGNSP PGUID 12 1 100 0 0 f f f f t t i 2 0 3802 "3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_unnest_value _null_ _null_ _null_ ));
48804882
DESCR("expand values from jsonb");
48814883
DATA(insert OID = 7647 ( unnest_key PGNSP PGUID 12 1 100 0 0 f f f f t t i 2 0 25 "3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_unnest_key _null_ _null_ _null_ ));

src/include/utils/jsonb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ extern Datum jsonb_concat(PG_FUNCTION_ARGS);
404404

405405
/* unnesting function */
406406
extern Datum jsonb_unnest_element(PG_FUNCTION_ARGS);
407+
extern Datum jsonb_unnest_element_index(PG_FUNCTION_ARGS);
407408
extern Datum jsonb_unnest_value(PG_FUNCTION_ARGS);
408409
extern Datum jsonb_unnest_key(PG_FUNCTION_ARGS);
409410

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy