Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+27-6
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

+42-5
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

+2
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

+1
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)