Skip to content

Commit 6703dff

Browse files
committed
Add more commentaries in core
Move up `jsonb_set_element` close to `jsonb_get_element`
1 parent 3950944 commit 6703dff

File tree

12 files changed

+135
-70
lines changed

12 files changed

+135
-70
lines changed

src/backend/catalog/heap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ AddNewRelationType(const char *typeName,
978978
0, /* array dimensions for typBaseType */
979979
false, /* Type NOT NULL */
980980
InvalidOid, /* rowtypes never have a collation */
981-
InvalidOid);
981+
InvalidOid); /* typsubscription - none */
982982
}
983983

984984
/* --------------------------------
@@ -1246,7 +1246,7 @@ heap_create_with_catalog(const char *relname,
12461246
0, /* array dimensions for typBaseType */
12471247
false, /* Type NOT NULL */
12481248
InvalidOid, /* rowtypes never have a collation */
1249-
F_ARRAY_SUBSCRIPTION);
1249+
F_ARRAY_SUBSCRIPTION); /* array implementation */
12501250

12511251
pfree(relarrayname);
12521252
}

src/backend/commands/typecmds.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ DefineType(List *names, List *parameters)
642642
0, /* Array Dimensions of typbasetype */
643643
false, /* Type NOT NULL */
644644
collation, /* type's collation */
645-
subscriptionOid);
645+
subscriptionOid); /* subscription procedure */
646646
Assert(typoid == address.objectId);
647647

648648
/*
@@ -1075,7 +1075,7 @@ DefineDomain(CreateDomainStmt *stmt)
10751075
typNDims, /* Array dimensions for base type */
10761076
typNotNull, /* Type NOT NULL */
10771077
domaincoll, /* type's collation */
1078-
subscriptionProcedure);
1078+
subscriptionProcedure); /* subscription procedure */
10791079

10801080
/*
10811081
* Process constraints which refer to the domain ID returned by TypeCreate
@@ -1188,7 +1188,7 @@ DefineEnum(CreateEnumStmt *stmt)
11881188
0, /* Array dimensions of typbasetype */
11891189
false, /* Type NOT NULL */
11901190
InvalidOid, /* type's collation */
1191-
InvalidOid);
1191+
InvalidOid); /* typsubscription - none */
11921192

11931193
/* Enter the enum's values into pg_enum */
11941194
EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
@@ -1229,7 +1229,7 @@ DefineEnum(CreateEnumStmt *stmt)
12291229
0, /* Array dimensions of typbasetype */
12301230
false, /* Type NOT NULL */
12311231
InvalidOid, /* type's collation */
1232-
F_ARRAY_SUBSCRIPTION);
1232+
F_ARRAY_SUBSCRIPTION); /* array subscription implementation */
12331233

12341234
pfree(enumArrayName);
12351235

@@ -1529,7 +1529,7 @@ DefineRange(CreateRangeStmt *stmt)
15291529
0, /* Array dimensions of typbasetype */
15301530
false, /* Type NOT NULL */
15311531
InvalidOid, /* type's collation (ranges never have one) */
1532-
InvalidOid);
1532+
InvalidOid); /* typsubscription - none */
15331533
Assert(typoid == address.objectId);
15341534

15351535
/* Create the entry in pg_range */
@@ -1572,7 +1572,7 @@ DefineRange(CreateRangeStmt *stmt)
15721572
0, /* Array dimensions of typbasetype */
15731573
false, /* Type NOT NULL */
15741574
InvalidOid, /* typcollation */
1575-
F_ARRAY_SUBSCRIPTION);
1575+
F_ARRAY_SUBSCRIPTION); /* array subscription implementation */
15761576

15771577
pfree(rangeArrayName);
15781578

src/backend/executor/execQual.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,12 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
253253
/*----------
254254
* ExecEvalSubscriptionRef
255255
*
256-
* This function takes an SubscriptionRef and returns the extracted Datum
257-
* if it's a simple reference, or the modified containers value if it's
258-
* an containers assignment (i.e., containers element or slice insertion).
256+
* This function takes a SubscriptionRef, extracts all information required
257+
* for subscription and pass it to a particular subscription procedure,
258+
* specified for this data type. As a result the extracted Datum will be
259+
* returned if it's a simple reference, or the modified containers value if
260+
* it's an containers assignment (i.e., containers element or slice
261+
* insertion).
259262
*
260263
* NOTE: if we get a NULL result from a subscript expression, we return NULL
261264
* when it's an containers reference, or raise an error when it's an assignment.

src/backend/parser/parse_node.c

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,18 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
201201

202202
/* NOTE: extra code for array type with isn't affect on other types
203203
* transformArrayType()
204-
* Identify the types involved in a subscripting operation
204+
* Identify the types involved in a subscripting operation for array
205205
*
206206
* On entry, arrayType/arrayTypmod identify the type of the input value
207207
* to be subscripted (which could be a domain type). These are modified
208208
* if necessary to identify the actual array type and typmod, and the
209209
* array's element type is returned. An error is thrown if the input isn't
210210
* an array type.
211+
*
212+
* NOTE: This part of type-specific code is not separated into type-specific
213+
* subscription procedure for now, but it does not affect on the whole logic,
214+
* since InvalidOid will be return in case of other types not an error.
215+
* An error will appears only if a subscription procedure is not defined.
211216
*/
212217
Oid
213218
transformArrayType(Oid *containerType, int32 *containerTypmod)
@@ -257,29 +262,36 @@ transformArrayType(Oid *containerType, int32 *containerTypmod)
257262
* Transform container subscripting. This is used for both
258263
* container fetch and container assignment.
259264
*
260-
* In a container fetch, we are given a source container value and we produce an
261-
* expression that represents the result of extracting a single container element
262-
* or a container slice.
265+
* In a container fetch, we are given a source container value and we produce
266+
* an expression that represents the result of extracting a single container
267+
* element or a container slice.
263268
*
264269
* In a container assignment, we are given a destination container value plus a
265-
* source value that is to be assigned to a single element or a slice of
266-
* that container. We produce an expression that represents the new container value
270+
* source value that is to be assigned to a single element or a slice of that
271+
* container. We produce an expression that represents the new container value
267272
* with the source data inserted into the right part of the container.
268273
*
269-
* For both cases, if the source container is of a domain-over-container type,
270-
* the result is of the base container type or its element type; essentially,
271-
* we must fold a domain to its base type before applying subscripting.
272-
* (Note that int2vector and oidvector are treated as domains here.)
274+
* For both cases, this function contains only general subscription logic while
275+
* type-specific logic (e.g. type verifications and coersion) is placend in
276+
* separate procedure indicated by typsubscription. There is only one exception
277+
* for now about domain-over-container, if the source container is of a
278+
* domain-over-container type, the result is of the base container type or its
279+
* element type; essentially, we must fold a domain to its base type before
280+
* applying subscripting. (Note that int2vector and oidvector are treated as
281+
* domains here.) If domain verification failed we assume, that element type
282+
* must be the same as container type (e.g. in case of jsonb).
283+
* An error will appear in case if current container type doesn't have a
284+
* subscription procedure.
273285
*
274-
* pstate Parse state
286+
* pstate Parse state
275287
* containerBase Already-transformed expression for the container as a whole
276288
* containerType OID of container's datatype (should match type of containerBase,
277-
* or be the base type of containerBase's domain type)
278-
* elementType OID of container's element type (fetch with transformcontainerType,
279-
* or pass InvalidOid to do it here)
289+
* or be the base type of containerBase's domain type)
290+
* elementType OID of container's element type (fetch with transformArrayType,
291+
* or pass InvalidOid to do it here)
280292
* containerTypMod typmod for the container (which is also typmod for the elements)
281-
* indirection Untransformed list of subscripts (must not be NIL)
282-
* assignFrom NULL for container fetch, else transformed expression for source.
293+
* indirection Untransformed list of subscripts (must not be NIL)
294+
* assignFrom NULL for container fetch, else transformed expression for source.
283295
*/
284296

285297
SubscriptionRef *

src/backend/parser/parse_target.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ transformAssignmentIndirection(ParseState *pstate,
776776
}
777777

778778
/*
779-
* helper for transformAssignmentIndirection: process array assignment
779+
* helper for transformAssignmentIndirection: process container assignment
780780
*/
781781
static Node *
782782
transformAssignmentSubscripts(ParseState *pstate,

src/backend/utils/adt/arrayfuncs.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6561,6 +6561,11 @@ isAssignmentIndirectionExpr(ExprState *exprstate)
65616561
return false;
65626562
}
65636563

6564+
/*
6565+
* Perform an actual data extraction or modification for the array
6566+
* subscription. As a result the extracted Datum or the modified containers
6567+
* value will be returned.
6568+
*/
65646569
Datum
65656570
array_subscription_evaluate(PG_FUNCTION_ARGS)
65666571
{
@@ -6722,6 +6727,13 @@ array_subscription_evaluate(PG_FUNCTION_ARGS)
67226727
sbstate->refelemalign);
67236728
}
67246729

6730+
/*
6731+
* Perform preparation for the array subscription, mostly type verification
6732+
* and coersion. This function produces an expression that represents the
6733+
* result of extracting a single container element/container slice or the new
6734+
* container value with the source data inserted into the right part of the
6735+
* container.
6736+
*/
67256737
Datum
67266738
array_subscription_prepare(PG_FUNCTION_ARGS)
67276739
{
@@ -6860,6 +6872,9 @@ array_subscription_prepare(PG_FUNCTION_ARGS)
68606872
PG_RETURN_POINTER(sbsref);
68616873
}
68626874

6875+
/*
6876+
* Handle array-type subscription logic.
6877+
*/
68636878
Datum
68646879
array_subscription(PG_FUNCTION_ARGS)
68656880
{

src/backend/utils/adt/jsonb.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,11 @@ to_jsonb(PG_FUNCTION_ARGS)
11491149
PG_RETURN_POINTER(JsonbValueToJsonb(res));
11501150
}
11511151

1152+
/*
1153+
* Do the actual conversion to jsonb for to_jsonb function. This logic is
1154+
* separated because it can be useful not only in here (e.g. we use it in
1155+
* jsonb subscription)
1156+
*/
11521157
JsonbValue *
11531158
to_jsonb_worker(Datum source, Oid source_type)
11541159
{

src/backend/utils/adt/jsonfuncs.c

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,32 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
13651365
}
13661366
}
13671367

1368+
Datum
1369+
jsonb_set_element(Datum jsonbdatum, Datum *path, int path_len,
1370+
Datum sourceData, Oid source_type)
1371+
{
1372+
Jsonb *jb = DatumGetJsonb(jsonbdatum);
1373+
JsonbValue *newval,
1374+
*res;
1375+
JsonbParseState *state = NULL;
1376+
JsonbIterator *it;
1377+
bool *path_nulls = palloc0(path_len * sizeof(bool));
1378+
1379+
newval = to_jsonb_worker(sourceData, source_type);
1380+
1381+
if (newval->type == jbvArray && newval->val.array.rawScalar)
1382+
*newval = newval->val.array.elems[0];
1383+
1384+
it = JsonbIteratorInit(&jb->root);
1385+
1386+
res = setPath(&it, path, path_nulls, path_len, &state, 0,
1387+
newval, JB_PATH_CREATE);
1388+
1389+
pfree(path_nulls);
1390+
1391+
PG_RETURN_JSONB(JsonbValueToJsonb(res));
1392+
}
1393+
13681394
/*
13691395
* SQL function json_array_length(json) -> int
13701396
*/
@@ -4033,12 +4059,17 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
40334059
if (op_type & JB_PATH_CREATE_OR_INSERT && !done &&
40344060
level == path_len - 1 && i == nelems - 1)
40354061
{
4036-
(void) pushJsonbValue(st, WJB_ELEM, newval);
4062+
(void) pushJsonbValue(st, WJB_ELEM, new);
40374063
}
40384064
}
40394065
}
40404066
}
40414067

4068+
/*
4069+
* Perform an actual data extraction or modification for the jsonb
4070+
* subscription. As a result the extracted Datum or the modified containers
4071+
* value will be returned.
4072+
*/
40424073
Datum
40434074
jsonb_subscription_evaluate(PG_FUNCTION_ARGS)
40444075
{
@@ -4120,6 +4151,14 @@ jsonb_subscription_evaluate(PG_FUNCTION_ARGS)
41204151
false);
41214152
}
41224153

4154+
/*
4155+
* Perform preparation for the jsonb subscription. Since there are not any
4156+
* particular restrictions for this kind of subscription, we will verify that
4157+
* it is not a slice operation. This function produces an expression that
4158+
* represents the result of extracting a single container element or the new
4159+
* container value with the source data inserted into the right part of the
4160+
* container.
4161+
*/
41234162
Datum
41244163
jsonb_subscription_prepare(PG_FUNCTION_ARGS)
41254164
{
@@ -4168,6 +4207,9 @@ jsonb_subscription_prepare(PG_FUNCTION_ARGS)
41684207
PG_RETURN_POINTER(sbsref);
41694208
}
41704209

4210+
/*
4211+
* Handle jsonb-type subscription logic.
4212+
*/
41714213
Datum
41724214
jsonb_subscription(PG_FUNCTION_ARGS)
41734215
{
@@ -4183,29 +4225,3 @@ jsonb_subscription(PG_FUNCTION_ARGS)
41834225

41844226
elog(ERROR, "incorrect op_type for subscription function: %d", op_type);
41854227
}
4186-
4187-
Datum
4188-
jsonb_set_element(Datum jsonbdatum, Datum *path, int path_len,
4189-
Datum sourceData, Oid source_type)
4190-
{
4191-
Jsonb *jb = DatumGetJsonb(jsonbdatum);
4192-
JsonbValue *newval,
4193-
*res;
4194-
JsonbParseState *state = NULL;
4195-
JsonbIterator *it;
4196-
bool *path_nulls = palloc0(path_len * sizeof(bool));
4197-
4198-
newval = to_jsonb_worker(sourceData, source_type);
4199-
4200-
if (newval->type == jbvArray && newval->val.array.rawScalar)
4201-
*newval = newval->val.array.elems[0];
4202-
4203-
it = JsonbIteratorInit(&jb->root);
4204-
4205-
res = setPath(&it, path, path_nulls, path_len, &state, 0,
4206-
newval, JB_PATH_CREATE);
4207-
4208-
pfree(path_nulls);
4209-
4210-
PG_RETURN_JSONB(JsonbValueToJsonb(res));
4211-
}

src/include/catalog/pg_type.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
198198
* collatable base types, possibly other OID for domains
199199
*/
200200
Oid typcollation;
201+
202+
/*
203+
* Type specific subscription logic. If typsubscription is none, it means
204+
* that this type doesn't support subscription.
205+
*/
201206
regproc typsubscription;
202207

203208
#ifdef CATALOG_VARLEN /* variable-length fields start here */
@@ -224,7 +229,6 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
224229
*/
225230
aclitem typacl[1];
226231
#endif
227-
228232
} FormData_pg_type;
229233

230234
/* ----------------

src/include/nodes/execnodes.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,12 +657,21 @@ typedef struct SubscriptionRefExprState
657657
List *reflowerindexpr;
658658
ExprState *refexpr;
659659
ExprState *refassgnexpr;
660-
int16 refattrlength; /* typlen of array type */
661-
int16 refelemlength; /* typlen of the array element type */
660+
int16 refattrlength; /* typlen of container type */
661+
int16 refelemlength; /* typlen of the container element type */
662662
bool refelembyval; /* is the element type pass-by-value? */
663663
char refelemalign; /* typalign of the element type */
664664
} SubscriptionRefExprState;
665665

666+
/* ---------------------------------
667+
* Subscription exec information
668+
*
669+
* It contains all information which is required to perform type-specific data
670+
* extraction or modification. This information will be gathered in
671+
* `ExecEvalSubscriptionRef` function and passed to `typsubscription`
672+
* procedure.
673+
* ---------------------------------
674+
*/
666675
typedef struct SubscriptionExecData
667676
{
668677
ExprContext *xprcontext; /* econtext for subscription */

0 commit comments

Comments
 (0)