0002-Base-implementation-of-subscripting-mechanism-v12.patch
text/x-patch
Filename: 0002-Base-implementation-of-subscripting-mechanism-v12.patch
Type: text/x-patch
Part: 3
Patch
Format: format-patch
Series: patch v12-0002
Subject: Base implementation of subscripting mechanism
| File | + | − |
|---|---|---|
| contrib/pg_stat_statements/pg_stat_statements.c | 1 | 0 |
| src/backend/catalog/heap.c | 4 | 2 |
| src/backend/catalog/pg_type.c | 15 | 1 |
| src/backend/commands/typecmds.c | 70 | 8 |
| src/backend/executor/execExpr.c | 13 | 27 |
| src/backend/executor/execExprInterp.c | 20 | 99 |
| src/backend/nodes/copyfuncs.c | 2 | 0 |
| src/backend/nodes/equalfuncs.c | 2 | 0 |
| src/backend/nodes/outfuncs.c | 2 | 0 |
| src/backend/nodes/readfuncs.c | 2 | 0 |
| src/backend/parser/parse_expr.c | 35 | 19 |
| src/backend/parser/parse_node.c | 88 | 171 |
| src/backend/parser/parse_target.c | 53 | 48 |
| src/backend/utils/adt/ruleutils.c | 10 | 10 |
| src/backend/utils/cache/lsyscache.c | 23 | 0 |
| src/include/catalog/pg_class.dat | 1 | 1 |
| src/include/catalog/pg_type.dat | 152 | 81 |
| src/include/catalog/pg_type.h | 9 | 1 |
| src/include/c.h | 2 | 0 |
| src/include/executor/execExpr.h | 14 | 13 |
| src/include/nodes/primnodes.h | 36 | 29 |
| src/include/nodes/subscripting.h | 42 | 0 |
| src/include/parser/parse_node.h | 11 | 8 |
| src/include/utils/lsyscache.h | 1 | 0 |
From a7964b86a42b8def193e25566226fe66bd4ecc61 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <dmitrii.dolgov@zalando.de>
Date: Fri, 20 Jul 2018 22:21:36 +0200
Subject: [PATCH 2/5] Base implementation of subscripting mechanism
---
contrib/pg_stat_statements/pg_stat_statements.c | 1 +
src/backend/catalog/heap.c | 6 +-
src/backend/catalog/pg_type.c | 16 +-
src/backend/commands/typecmds.c | 78 ++++++-
src/backend/executor/execExpr.c | 40 ++--
src/backend/executor/execExprInterp.c | 119 ++---------
src/backend/nodes/copyfuncs.c | 2 +
src/backend/nodes/equalfuncs.c | 2 +
src/backend/nodes/outfuncs.c | 2 +
src/backend/nodes/readfuncs.c | 2 +
src/backend/parser/parse_expr.c | 54 +++--
src/backend/parser/parse_node.c | 259 ++++++++----------------
src/backend/parser/parse_target.c | 101 ++++-----
src/backend/utils/adt/ruleutils.c | 20 +-
src/backend/utils/cache/lsyscache.c | 23 +++
src/include/c.h | 2 +
src/include/catalog/pg_class.dat | 2 +-
src/include/catalog/pg_type.dat | 233 +++++++++++++--------
src/include/catalog/pg_type.h | 10 +-
src/include/executor/execExpr.h | 27 +--
src/include/nodes/primnodes.h | 65 +++---
src/include/nodes/subscripting.h | 42 ++++
src/include/parser/parse_node.h | 19 +-
src/include/utils/lsyscache.h | 1 +
24 files changed, 608 insertions(+), 518 deletions(-)
create mode 100644 src/include/nodes/subscripting.h
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index c734e04..01a67ce 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2513,6 +2513,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
JumbleExpr(jstate, (Node *) sbsref->refexpr);
JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
+ APP_JUMB(sbsref->refnestedfunc);
}
break;
case T_FuncExpr:
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index d223ba8..c5e29cf 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -986,7 +986,8 @@ AddNewRelationType(const char *typeName,
-1, /* typmod */
0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */
- InvalidOid); /* rowtypes never have a collation */
+ InvalidOid, /* rowtypes never have a collation */
+ InvalidOid); /* typsubshandler - none */
}
/* --------------------------------
@@ -1259,7 +1260,8 @@ heap_create_with_catalog(const char *relname,
-1, /* typmod */
0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */
- InvalidOid); /* rowtypes never have a collation */
+ InvalidOid, /* rowtypes never have a collation */
+ F_ARRAY_SUBSCRIPT_HANDLER); /* array implementation */
pfree(relarrayname);
}
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 2ddd46d..4bae288 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -117,6 +117,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
+ values[Anum_pg_type_typsubshandler - 1] = ObjectIdGetDatum(InvalidOid);
nulls[Anum_pg_type_typdefaultbin - 1] = true;
nulls[Anum_pg_type_typdefault - 1] = true;
nulls[Anum_pg_type_typacl - 1] = true;
@@ -163,6 +164,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
false,
InvalidOid,
InvalidOid,
+ InvalidOid,
NULL,
false);
@@ -221,7 +223,8 @@ TypeCreate(Oid newTypeOid,
int32 typeMod,
int32 typNDims, /* Array dimensions for baseType */
bool typeNotNull,
- Oid typeCollation)
+ Oid typeCollation,
+ Oid subscriptingHandlerProcedure)
{
Relation pg_type_desc;
Oid typeObjectId;
@@ -361,6 +364,7 @@ TypeCreate(Oid newTypeOid,
values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
+ values[Anum_pg_type_typsubshandler - 1] = ObjectIdGetDatum(subscriptingHandlerProcedure);
/*
* initialize the default binary value for this type. Check for nulls of
@@ -478,6 +482,7 @@ TypeCreate(Oid newTypeOid,
isImplicitArray,
baseType,
typeCollation,
+ subscriptingHandlerProcedure,
(defaultTypeBin ?
stringToNode(defaultTypeBin) :
NULL),
@@ -524,6 +529,7 @@ GenerateTypeDependencies(Oid typeNamespace,
bool isImplicitArray,
Oid baseType,
Oid typeCollation,
+ Oid subscriptingHandlerProcedure,
Node *defaultExpr,
bool rebuild)
{
@@ -676,6 +682,14 @@ GenerateTypeDependencies(Oid typeNamespace,
/* Normal dependency on the default expression. */
if (defaultExpr)
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
+ if (OidIsValid(subscriptingHandlerProcedure))
+ {
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = subscriptingHandlerProcedure;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
}
/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 175ecc8..6b992c7 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -91,6 +91,7 @@ static Oid findTypeSendFunction(List *procname, Oid typeOid);
static Oid findTypeTypmodinFunction(List *procname);
static Oid findTypeTypmodoutFunction(List *procname);
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
+static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid, bool parseFunc);
static Oid findRangeSubOpclass(List *opcname, Oid subtype);
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
@@ -122,6 +123,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
List *typmodinName = NIL;
List *typmodoutName = NIL;
List *analyzeName = NIL;
+ List *subscriptingParseName = NIL;
char category = TYPCATEGORY_USER;
bool preferred = false;
char delimiter = DEFAULT_TYPDELIM;
@@ -140,6 +142,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *typmodinNameEl = NULL;
DefElem *typmodoutNameEl = NULL;
DefElem *analyzeNameEl = NULL;
+ DefElem *subscriptingParseNameEl = NULL;
DefElem *categoryEl = NULL;
DefElem *preferredEl = NULL;
DefElem *delimiterEl = NULL;
@@ -162,6 +165,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
Oid resulttype;
ListCell *pl;
ObjectAddress address;
+ Oid subscriptingParseOid = InvalidOid;
/*
* As of Postgres 8.4, we require superuser privilege to create a base
@@ -261,6 +265,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
else if (strcmp(defel->defname, "analyze") == 0 ||
strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
+ else if (strcmp(defel->defname, "subscripting_handler") == 0)
+ defelp = &subscriptingParseNameEl;
else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
else if (strcmp(defel->defname, "preferred") == 0)
@@ -331,6 +337,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
typmodoutName = defGetQualifiedName(typmodoutNameEl);
if (analyzeNameEl)
analyzeName = defGetQualifiedName(analyzeNameEl);
+ if (subscriptingParseNameEl)
+ subscriptingParseName = defGetQualifiedName(subscriptingParseNameEl);
if (categoryEl)
{
char *p = defGetString(categoryEl);
@@ -512,6 +520,10 @@ DefineType(ParseState *pstate, List *names, List *parameters)
if (analyzeName)
analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
+ if (subscriptingParseName)
+ subscriptingParseOid = findTypeSubscriptingFunction(subscriptingParseName,
+ typoid, true);
+
/*
* Check permissions on functions. We choose to require the creator/owner
* of a type to also own the underlying functions. Since creating a type
@@ -631,7 +643,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
-1, /* typMod (Domains only) */
0, /* Array Dimensions of typbasetype */
false, /* Type NOT NULL */
- collation); /* type's collation */
+ collation, /* type's collation */
+ subscriptingParseOid); /* subscripting procedure */
Assert(typoid == address.objectId);
/*
@@ -672,7 +685,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- collation); /* type's collation */
+ collation, /* type's collation */
+ F_ARRAY_SUBSCRIPT_HANDLER);
pfree(array_type);
@@ -735,6 +749,7 @@ DefineDomain(CreateDomainStmt *stmt)
Oid receiveProcedure;
Oid sendProcedure;
Oid analyzeProcedure;
+ Oid subscriptingHandlerProcedure;
bool byValue;
char category;
char delimiter;
@@ -862,6 +877,9 @@ DefineDomain(CreateDomainStmt *stmt)
/* Analysis function */
analyzeProcedure = baseType->typanalyze;
+ /* Subscripting functions */
+ subscriptingHandlerProcedure = baseType->typsubshandler;
+
/* Inherited default value */
datum = SysCacheGetAttr(TYPEOID, typeTup,
Anum_pg_type_typdefault, &isnull);
@@ -1066,7 +1084,8 @@ DefineDomain(CreateDomainStmt *stmt)
basetypeMod, /* typeMod value */
typNDims, /* Array dimensions for base type */
typNotNull, /* Type NOT NULL */
- domaincoll); /* type's collation */
+ domaincoll, /* type's collation */
+ subscriptingHandlerProcedure); /* subscripting procedure */
/*
* Create the array type that goes with it.
@@ -1106,7 +1125,8 @@ DefineDomain(CreateDomainStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- domaincoll); /* type's collation */
+ domaincoll, /* type's collation */
+ F_ARRAY_SUBSCRIPT_HANDLER); /* array subscripting implementation */
pfree(domainArrayName);
@@ -1221,7 +1241,8 @@ DefineEnum(CreateEnumStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* type's collation */
+ InvalidOid, /* type's collation */
+ InvalidOid); /* typsubshandler - none */
/* Enter the enum's values into pg_enum */
EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
@@ -1261,7 +1282,8 @@ DefineEnum(CreateEnumStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* type's collation */
+ InvalidOid, /* type's collation */
+ F_ARRAY_SUBSCRIPT_HANDLER); /* array subscripting implementation */
pfree(enumArrayName);
@@ -1570,7 +1592,8 @@ DefineRange(CreateRangeStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* type's collation (ranges never have one) */
+ InvalidOid, /* type's collation (ranges never have one) */
+ InvalidOid); /* typsubshandler - none */
Assert(typoid == address.objectId);
/* Create the entry in pg_range */
@@ -1612,7 +1635,8 @@ DefineRange(CreateRangeStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* typcollation */
+ InvalidOid, /* typcollation */
+ F_ARRAY_SUBSCRIPT_HANDLER); /* array subscripting implementation */
pfree(rangeArrayName);
@@ -1955,6 +1979,43 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
return procOid;
}
+static Oid
+findTypeSubscriptingFunction(List *procname, Oid typeOid, bool parseFunc)
+{
+ Oid argList[2];
+ Oid procOid;
+ int nargs;
+
+ if (parseFunc)
+ {
+ /*
+ * Subscripting function parse always take two INTERNAL argument and
+ * return INTERNAL.
+ */
+ argList[0] = INTERNALOID;
+ nargs = 1;
+ }
+ else
+ {
+ /*
+ * Subscripting functions fetch/assign always take one typeOid
+ * argument, one INTERNAL argument and return typeOid.
+ */
+ argList[0] = typeOid;
+ argList[1] = INTERNALOID;
+ nargs = 2;
+ }
+
+ procOid = LookupFuncName(procname, nargs, argList, true);
+ if (!OidIsValid(procOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, nargs, NIL, argList))));
+
+ return procOid;
+}
+
/*
* Find suitable support functions and opclasses for a range type.
*/
@@ -2308,6 +2369,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
false, /* a domain isn't an implicit array */
typTup->typbasetype,
typTup->typcollation,
+ typTup->typsubshandler,
defaultExpr,
true); /* Rebuild is true */
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 3d8d05b..08a41cb 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2436,20 +2436,18 @@ static void
ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
ExprState *state, Datum *resv, bool *resnull)
{
- bool isAssignment = (aref->refassgnexpr != NULL);
- ArrayRefState *arefstate = palloc0(sizeof(ArrayRefState));
- List *adjust_jumps = NIL;
- ListCell *lc;
- int i;
-
- /* Fill constant fields of ArrayRefState */
- arefstate->isassignment = isAssignment;
- arefstate->refelemtype = aref->refelemtype;
- arefstate->refattrlength = get_typlen(aref->refarraytype);
- get_typlenbyvalalign(aref->refelemtype,
- &arefstate->refelemlength,
- &arefstate->refelembyval,
- &arefstate->refelemalign);
+ bool isAssignment = (sbsref->refassgnexpr != NULL);
+ SubscriptingRefState *sbsrefstate = palloc0(sizeof(SubscriptingRefState));
+ List *adjust_jumps = NIL;
+ ListCell *lc;
+ int i;
+ RegProcedure typsubshandler = get_typsubsprocs(sbsref->refcontainertype);
+
+ /* Fill constant fields of SubscriptingRefState */
+ sbsrefstate->isassignment = isAssignment;
+ sbsrefstate->refelemtype = sbsref->refelemtype;
+ sbsrefstate->refattrlength = get_typlen(sbsref->refcontainertype);
+ sbsrefstate->sbsroutines = (SubscriptRoutines *) OidFunctionCall0(typsubshandler);
/*
* Evaluate array input. It's safe to do so into resv/resnull, because we
@@ -2469,23 +2467,11 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
scratch->opcode = EEOP_JUMP_IF_NULL;
scratch->d.jump.jumpdone = -1; /* adjust later */
ExprEvalPushStep(state, scratch);
+
adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1);
}
- /* Verify subscript list lengths are within limit */
- if (list_length(aref->refupperindexpr) > MAXDIM)
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
- list_length(aref->refupperindexpr), MAXDIM)));
-
- if (list_length(aref->reflowerindexpr) > MAXDIM)
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
- list_length(aref->reflowerindexpr), MAXDIM)));
-
/* Evaluate upper subscripts */
i = 0;
foreach(lc, sbsref->refupperindexpr)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 3299fe5..1d1d85a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3078,7 +3078,7 @@ ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
indexes = sbsrefstate->lowerindex;
off = op->d.sbsref_subscript.off;
- indexes[off] = DatumGetInt32(arefstate->subscriptvalue);
+ indexes[off] = sbsrefstate->subscriptvalue;
return true;
}
@@ -3091,37 +3091,14 @@ ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
void
ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref.state;
+ SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
+ SubscriptRoutines *sbsroutines = sbsrefstate->sbsroutines;
/* Should not get here if source container (or any subscript) is null */
Assert(!(*op->resnull));
- if (arefstate->numlower == 0)
- {
- /* Scalar case */
- *op->resvalue = array_get_element(*op->resvalue,
- arefstate->numupper,
- arefstate->upperindex,
- arefstate->refattrlength,
- arefstate->refelemlength,
- arefstate->refelembyval,
- arefstate->refelemalign,
- op->resnull);
- }
- else
- {
- /* Slice case */
- *op->resvalue = array_get_slice(*op->resvalue,
- arefstate->numupper,
- arefstate->upperindex,
- arefstate->lowerindex,
- arefstate->upperprovided,
- arefstate->lowerprovided,
- arefstate->refattrlength,
- arefstate->refelemlength,
- arefstate->refelembyval,
- arefstate->refelemalign);
- }
+ *op->resvalue = sbsroutines->fetch(*op->resvalue, sbsrefstate);
+ *op->resnull = sbsrefstate->resnull;
}
/*
@@ -3133,41 +3110,22 @@ ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op)
void
ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref.state;
+ SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
+ SubscriptRoutines *sbsroutines = sbsrefstate->sbsroutines;
if (*op->resnull)
{
- /* whole array is null, so any element or slice is too */
- arefstate->prevvalue = (Datum) 0;
- arefstate->prevnull = true;
- }
- else if (arefstate->numlower == 0)
- {
- /* Scalar case */
- arefstate->prevvalue = array_get_element(*op->resvalue,
- arefstate->numupper,
- arefstate->upperindex,
- arefstate->refattrlength,
- arefstate->refelemlength,
- arefstate->refelembyval,
- arefstate->refelemalign,
- &arefstate->prevnull);
+ /* whole container is null, so any element or slice is too */
+ sbsrefstate->prevvalue = (Datum) 0;
+ sbsrefstate->prevnull = true;
}
else
{
- /* Slice case */
- /* this is currently unreachable */
- arefstate->prevvalue = array_get_slice(*op->resvalue,
- arefstate->numupper,
- arefstate->upperindex,
- arefstate->lowerindex,
- arefstate->upperprovided,
- arefstate->lowerprovided,
- arefstate->refattrlength,
- arefstate->refelemlength,
- arefstate->refelembyval,
- arefstate->refelemalign);
- arefstate->prevnull = false;
+ sbsrefstate->prevvalue = sbsroutines->fetch(*op->resvalue, sbsrefstate);
+
+ if (sbsrefstate->numlower != 0)
+ sbsrefstate->prevnull = false;
+
}
}
@@ -3180,7 +3138,8 @@ ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op)
void
ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref.state;
+ SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
+ SubscriptRoutines *sbsroutines = sbsrefstate->sbsroutines;
/*
* For an assignment to a fixed-length container type, both the original
@@ -3193,47 +3152,9 @@ ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op)
return;
}
- /*
- * For assignment to varlena arrays, we handle a NULL original array by
- * substituting an empty (zero-dimensional) array; insertion of the new
- * element will result in a singleton array value. It does not matter
- * whether the new element is NULL.
- */
- if (*op->resnull)
- {
- *op->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype));
- *op->resnull = false;
- }
-
- if (arefstate->numlower == 0)
- {
- /* Scalar case */
- *op->resvalue = array_set_element(*op->resvalue,
- arefstate->numupper,
- arefstate->upperindex,
- arefstate->replacevalue,
- arefstate->replacenull,
- arefstate->refattrlength,
- arefstate->refelemlength,
- arefstate->refelembyval,
- arefstate->refelemalign);
- }
- else
- {
- /* Slice case */
- *op->resvalue = array_set_slice(*op->resvalue,
- arefstate->numupper,
- arefstate->upperindex,
- arefstate->lowerindex,
- arefstate->upperprovided,
- arefstate->lowerprovided,
- arefstate->replacevalue,
- arefstate->replacenull,
- arefstate->refattrlength,
- arefstate->refelemlength,
- arefstate->refelembyval,
- arefstate->refelemalign);
- }
+ sbsrefstate->resnull = *op->resnull;
+ *op->resvalue = sbsroutines->assign(*op->resvalue, sbsrefstate);
+ *op->resnull = sbsrefstate->resnull;
}
/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f67f14e..96e45c9 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1486,8 +1486,10 @@ _copySubscriptingRef(const SubscriptingRef *from)
COPY_SCALAR_FIELD(refcontainertype);
COPY_SCALAR_FIELD(refelemtype);
+ COPY_SCALAR_FIELD(refassgntype);
COPY_SCALAR_FIELD(reftypmod);
COPY_SCALAR_FIELD(refcollid);
+ COPY_SCALAR_FIELD(refnestedfunc);
COPY_NODE_FIELD(refupperindexpr);
COPY_NODE_FIELD(reflowerindexpr);
COPY_NODE_FIELD(refexpr);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 73c91bc..c7a9c2c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -268,8 +268,10 @@ _equalSubscriptingRef(const SubscriptingRef *a, const SubscriptingRef *b)
{
COMPARE_SCALAR_FIELD(refcontainertype);
COMPARE_SCALAR_FIELD(refelemtype);
+ COMPARE_SCALAR_FIELD(refassgntype);
COMPARE_SCALAR_FIELD(reftypmod);
COMPARE_SCALAR_FIELD(refcollid);
+ COMPARE_SCALAR_FIELD(refnestedfunc);
COMPARE_NODE_FIELD(refupperindexpr);
COMPARE_NODE_FIELD(reflowerindexpr);
COMPARE_NODE_FIELD(refexpr);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 70a48d6..b0c8baa 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1246,8 +1246,10 @@ _outSubscriptingRef(StringInfo str, const SubscriptingRef *node)
WRITE_OID_FIELD(refcontainertype);
WRITE_OID_FIELD(refelemtype);
+ WRITE_OID_FIELD(refassgntype);
WRITE_INT_FIELD(reftypmod);
WRITE_OID_FIELD(refcollid);
+ WRITE_OID_FIELD(refnestedfunc);
WRITE_NODE_FIELD(refupperindexpr);
WRITE_NODE_FIELD(reflowerindexpr);
WRITE_NODE_FIELD(refexpr);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 167932c..a4f53e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -654,8 +654,10 @@ _readSubscriptingRef(void)
READ_OID_FIELD(refcontainertype);
READ_OID_FIELD(refelemtype);
+ READ_OID_FIELD(refassgntype);
READ_INT_FIELD(reftypmod);
READ_OID_FIELD(refcollid);
+ READ_OID_FIELD(refnestedfunc);
READ_NODE_FIELD(refupperindexpr);
READ_NODE_FIELD(reflowerindexpr);
READ_NODE_FIELD(refexpr);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 385e54a..5ef606b 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -434,11 +434,13 @@ unknown_attribute(ParseState *pstate, Node *relref, const char *attname,
static Node *
transformIndirection(ParseState *pstate, A_Indirection *ind)
{
- Node *last_srf = pstate->p_last_srf;
- Node *result = transformExprRecurse(pstate, ind->arg);
- List *subscripts = NIL;
- int location = exprLocation(result);
- ListCell *i;
+ Node *last_srf = pstate->p_last_srf;
+ Node *result = transformExprRecurse(pstate, ind->arg);
+ SubscriptRoutines *sbsroutines;
+ SubscriptingRef *sbsref;
+ List *subscripts = NIL;
+ int location = exprLocation(result);
+ ListCell *i;
/*
* We have to split any field-selection operations apart from
@@ -466,13 +468,20 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
/* process subscripts before this field selection */
if (subscripts)
- result = (Node *) transformArraySubscripts(pstate,
- result,
- exprType(result),
- InvalidOid,
- exprTypmod(result),
- subscripts,
- NULL);
+ {
+ sbsref = transformContainerSubscripts(pstate,
+ result,
+ exprType(result),
+ InvalidOid,
+ exprTypmod(result),
+ subscripts,
+ NULL);
+
+ sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype);
+ sbsref = sbsroutines->prepare(false, sbsref);
+ sbsroutines->validate(false, sbsref, pstate);
+ result = (Node *) sbsref;
+ }
subscripts = NIL;
newresult = ParseFuncOrColumn(pstate,
@@ -489,13 +498,20 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
}
/* process trailing subscripts, if any */
if (subscripts)
- result = (Node *) transformArraySubscripts(pstate,
- result,
- exprType(result),
- InvalidOid,
- exprTypmod(result),
- subscripts,
- NULL);
+ {
+ sbsref = transformContainerSubscripts(pstate,
+ result,
+ exprType(result),
+ InvalidOid,
+ exprTypmod(result),
+ subscripts,
+ NULL);
+
+ sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype);
+ sbsref = sbsroutines->prepare(false, sbsref);
+ sbsroutines->validate(false, sbsref, pstate);
+ result = (Node *) sbsref;
+ }
return result;
}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index d267288..f032f8e 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -203,31 +203,23 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
}
/*
- * transformArrayType()
- * Identify the types involved in a subscripting operation
+ * transformContainerType()
+ * Identify the types involved in a subscripting operation for container
*
- * On entry, arrayType/arrayTypmod identify the type of the input value
- * to be subscripted (which could be a domain type). These are modified
- * if necessary to identify the actual array type and typmod, and the
- * array's element type is returned. An error is thrown if the input isn't
- * an array type.
+ * On entry, containerType/containerTypmod are modified if necessary to
+ * identify the actual container type and typmod.
*/
-Oid
-transformArrayType(Oid *arrayType, int32 *arrayTypmod)
+void
+transformContainerType(Oid *containerType, int32 *containerTypmod)
{
- Oid origArrayType = *arrayType;
- Oid elementType;
- HeapTuple type_tuple_array;
- Form_pg_type type_struct_array;
-
/*
* If the input is a domain, smash to base type, and extract the actual
- * typmod to be applied to the base type. Subscripting a domain is an
- * operation that necessarily works on the base array type, not the domain
- * itself. (Note that we provide no method whereby the creator of a
- * domain over an array type could hide its ability to be subscripted.)
+ * typmod to be applied to the base type. Subscripting a domain is an
+ * operation that necessarily works on the base container type, not the
+ * domain itself. (Note that we provide no method whereby the creator of a
+ * domain over a container type could hide its ability to be subscripted.)
*/
- *arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod);
+ *containerType = getBaseTypeAndTypmod(*containerType, containerTypmod);
/*
* We treat int2vector and oidvector as though they were domains over
@@ -236,87 +228,70 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod)
* xxxvector type; so we want the result of a slice operation to be
* considered to be of the more general type.
*/
- if (*arrayType == INT2VECTOROID)
- *arrayType = INT2ARRAYOID;
- else if (*arrayType == OIDVECTOROID)
- *arrayType = OIDARRAYOID;
-
- /* Get the type tuple for the array */
- type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType));
- if (!HeapTupleIsValid(type_tuple_array))
- elog(ERROR, "cache lookup failed for type %u", *arrayType);
- type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array);
-
- /* needn't check typisdefined since this will fail anyway */
-
- elementType = type_struct_array->typelem;
- if (elementType == InvalidOid)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot subscript type %s because it is not an array",
- format_type_be(origArrayType))));
-
- ReleaseSysCache(type_tuple_array);
-
- return elementType;
+ if (*containerType == INT2VECTOROID)
+ *containerType = INT2ARRAYOID;
+ else if (*containerType == OIDVECTOROID)
+ *containerType = OIDARRAYOID;
}
/*
- * transformArraySubscripts()
- * Transform array subscripting. This is used for both
- * array fetch and array assignment.
+ * transformContainerSubscripts()
+ * Transform container subscripting. This is used for both
+ * container fetch and container assignment.
*
- * In an array fetch, we are given a source array value and we produce an
- * expression that represents the result of extracting a single array element
- * or an array slice.
+ * In a container fetch, we are given a source container value and we produce
+ * an expression that represents the result of extracting a single container
+ * element or a container slice.
*
- * In an array assignment, we are given a destination array value plus a
- * source value that is to be assigned to a single element or a slice of
- * that array. We produce an expression that represents the new array value
- * with the source data inserted into the right part of the array.
+ * In a container assignment, we are given a destination container value plus a
+ * source value that is to be assigned to a single element or a slice of that
+ * container. We produce an expression that represents the new container value
+ * with the source data inserted into the right part of the container.
*
- * For both cases, if the source array is of a domain-over-array type,
- * the result is of the base array type or its element type; essentially,
- * we must fold a domain to its base type before applying subscripting.
- * (Note that int2vector and oidvector are treated as domains here.)
+ * For both cases, this function contains only general subscripting logic while
+ * type-specific logic (e.g. type verifications and coersion) is placen in
+ * separate procedure indicated by typsubshandler. There is only one exception
+ * for now about domain-over-container, if the source container is of a
+ * domain-over-container type, the result is of the base container type or its
+ * element type; essentially, we must fold a domain to its base type before
+ * applying subscripting. (Note that int2vector and oidvector are treated as
+ * domains here.) An error will appear in case if current container type
+ * doesn't have a subscripting procedure.
*
- * pstate Parse state
- * arrayBase Already-transformed expression for the array as a whole
- * arrayType OID of array's datatype (should match type of arrayBase,
- * or be the base type of arrayBase's domain type)
- * elementType OID of array's element type (fetch with transformArrayType,
- * or pass InvalidOid to do it here)
- * arrayTypMod typmod for the array (which is also typmod for the elements)
- * indirection Untransformed list of subscripts (must not be NIL)
- * assignFrom NULL for array fetch, else transformed expression for source.
+ * pstate Parse state
+ * containerBase Already-transformed expression for the container as a whole
+ * containerType OID of container's datatype (should match type of containerBase,
+ * or be the base type of containerBase's domain type)
+ * elementType OID of container's element type (fetch with
+ * transformContainerType, or pass InvalidOid to do it here)
+ * containerTypMod typmod for the container (which is also typmod for the elements)
+ * indirection Untransformed list of subscripts (must not be NIL)
+ * assignFrom NULL for container fetch, else transformed expression for source.
*/
-ArrayRef *
-transformArraySubscripts(ParseState *pstate,
- Node *arrayBase,
- Oid arrayType,
- Oid elementType,
- int32 arrayTypMod,
- List *indirection,
- Node *assignFrom)
+
+SubscriptingRef *
+transformContainerSubscripts(ParseState *pstate,
+ Node *containerBase,
+ Oid containerType,
+ Oid elementType,
+ int32 containerTypMod,
+ List *indirection,
+ Node *assignFrom)
{
- bool isSlice = false;
- List *upperIndexpr = NIL;
- List *lowerIndexpr = NIL;
- ListCell *idx;
- ArrayRef *aref;
+ bool isSlice = false;
+ List *upperIndexpr = NIL;
+ List *lowerIndexpr = NIL;
+ List *indexprSlice = NIL;
+ ListCell *idx;
+ SubscriptingRef *sbsref;
- /*
- * Caller may or may not have bothered to determine elementType. Note
- * that if the caller did do so, arrayType/arrayTypMod must be as modified
- * by transformArrayType, ie, smash domain to base type.
- */
- if (!OidIsValid(elementType))
- elementType = transformArrayType(&arrayType, &arrayTypMod);
+ /* Identify the actual container type and element type involved */
+ transformContainerType(&containerType, &containerTypMod);
/*
- * A list containing only simple subscripts refers to a single array
+ * A list containing only simple subscripts refers to a single container
* element. If any of the items are slice specifiers (lower:upper), then
- * the subscript expression means an array slice operation. In this case,
+ * the subscript expression means an container slice operation. In this case,
* we convert any non-slice items to slices by treating the single
* subscript as the upper bound and supplying an assumed lower bound of 1.
* We have to prescan the list to see if there are any slice items.
@@ -345,29 +320,6 @@ transformArraySubscripts(ParseState *pstate,
if (ai->lidx)
{
subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
- /* If it's not int4 already, try to coerce */
- subexpr = coerce_to_target_type(pstate,
- subexpr, exprType(subexpr),
- INT4OID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST,
- -1);
- if (subexpr == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer"),
- parser_errposition(pstate, exprLocation(ai->lidx))));
- }
- else if (!ai->is_slice)
- {
- /* Make a constant 1 */
- subexpr = (Node *) makeConst(INT4OID,
- -1,
- InvalidOid,
- sizeof(int32),
- Int32GetDatum(1),
- false,
- true); /* pass by value */
}
else
{
@@ -375,77 +327,42 @@ transformArraySubscripts(ParseState *pstate,
subexpr = NULL;
}
lowerIndexpr = lappend(lowerIndexpr, subexpr);
+ indexprSlice = lappend(indexprSlice, ai);
}
- else
- Assert(ai->lidx == NULL && !ai->is_slice);
-
- if (ai->uidx)
- {
- subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
- /* If it's not int4 already, try to coerce */
- subexpr = coerce_to_target_type(pstate,
- subexpr, exprType(subexpr),
- INT4OID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST,
- -1);
- if (subexpr == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer"),
- parser_errposition(pstate, exprLocation(ai->uidx))));
- }
- else
- {
- /* Slice with omitted upper bound, put NULL into the list */
- Assert(isSlice && ai->is_slice);
- subexpr = NULL;
- }
+ subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
upperIndexpr = lappend(upperIndexpr, subexpr);
}
/*
- * If doing an array store, coerce the source value to the right type.
- * (This should agree with the coercion done by transformAssignedExpr.)
+ * Ready to build the SubscriptingRef node.
*/
+ sbsref = (SubscriptingRef *) makeNode(SubscriptingRef);
if (assignFrom != NULL)
- {
- Oid typesource = exprType(assignFrom);
- Oid typeneeded = isSlice ? arrayType : elementType;
- Node *newFrom;
-
- newFrom = coerce_to_target_type(pstate,
- assignFrom, typesource,
- typeneeded, arrayTypMod,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST,
- -1);
- if (newFrom == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array assignment requires type %s"
- " but expression is of type %s",
- format_type_be(typeneeded),
- format_type_be(typesource)),
- errhint("You will need to rewrite or cast the expression."),
- parser_errposition(pstate, exprLocation(assignFrom))));
- assignFrom = newFrom;
- }
+ sbsref->refassgnexpr = (Expr *) assignFrom;
- /*
- * Ready to build the ArrayRef node.
- */
- aref = makeNode(ArrayRef);
- aref->refarraytype = arrayType;
- aref->refelemtype = elementType;
- aref->reftypmod = arrayTypMod;
+ sbsref->refcontainertype = containerType;
+ sbsref->reftypmod = containerTypMod;
/* refcollid will be set by parse_collate.c */
- aref->refupperindexpr = upperIndexpr;
- aref->reflowerindexpr = lowerIndexpr;
- aref->refexpr = (Expr *) arrayBase;
- aref->refassgnexpr = (Expr *) assignFrom;
+ sbsref->refupperindexpr = upperIndexpr;
+ sbsref->reflowerindexpr = lowerIndexpr;
+ sbsref->refindexprslice = indexprSlice;
+ sbsref->refexpr = (Expr *) containerBase;
+
+ return sbsref;
+}
+
+SubscriptRoutines*
+getSubscriptingRoutines(Oid containerType)
+{
+ RegProcedure typsubshandler = get_typsubsprocs(containerType);
+
+ if (!OidIsValid(typsubshandler))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("cannot subscript type %s because it does not support subscripting",
+ format_type_be(containerType))));
- return aref;
+ return (SubscriptRoutines *) OidFunctionCall0(typsubshandler);
}
/*
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index d78376c..32efd18 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -838,27 +838,22 @@ transformAssignmentIndirection(ParseState *pstate,
location);
}
- /* base case: just coerce RHS to match target type ID */
-
- result = coerce_to_target_type(pstate,
- rhs, exprType(rhs),
- targetTypeId, targetTypMod,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST,
- -1);
- if (result == NULL)
+ /*
+ * Base case: just coerce RHS to match target type ID.
+ * It's necessary only for field selection, since for
+ * subscripting it's custom code who should define types.
+ */
+ if (!targetIsSubscripting)
{
- if (targetIsArray)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array assignment to \"%s\" requires type %s"
- " but expression is of type %s",
- targetName,
- format_type_be(targetTypeId),
- format_type_be(exprType(rhs))),
- errhint("You will need to rewrite or cast the expression."),
- parser_errposition(pstate, location)));
- else
+ result = coerce_to_target_type(pstate,
+ rhs, exprType(rhs),
+ targetTypeId, targetTypMod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+
+ if (result == NULL)
+ {
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("subfield \"%s\" is of type %s"
@@ -892,58 +887,68 @@ transformAssignmentSubscripts(ParseState *pstate,
Node *rhs,
int location)
{
- Node *result;
- Oid arrayType;
- int32 arrayTypMod;
- Oid elementTypeId;
- Oid typeNeeded;
- Oid collationNeeded;
+ Node *result;
+ Oid containerType;
+ int32 containerTypMod;
+ Oid collationNeeded;
+ SubscriptingRef *sbsref;
+ SubscriptRoutines *sbsroutines;
Assert(subscripts != NIL);
- /* Identify the actual array type and element type involved */
- arrayType = targetTypeId;
- arrayTypMod = targetTypMod;
- elementTypeId = transformArrayType(&arrayType, &arrayTypMod);
+ /* Identify the actual container type and element type involved */
+ containerType = targetTypeId;
+ containerTypMod = targetTypMod;
+
+ /* process subscripts */
+ sbsref = transformContainerSubscripts(pstate,
+ basenode,
+ containerType,
+ exprType(rhs),
+ containerTypMod,
+ subscripts,
+ rhs);
+
+ sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype);
- /* Identify type that RHS must provide */
- typeNeeded = isSlice ? arrayType : elementTypeId;
+ /*
+ * Let custom code provide necessary information about required types:
+ * refelemtype and refassgntype
+ */
+ sbsref = sbsroutines->prepare(rhs != NULL, sbsref);
/*
* container normally has same collation as elements, but there's an
* exception: we might be subscripting a domain over an container type. In
* that case use collation of the base type.
*/
- if (arrayType == targetTypeId)
+ if (sbsref->refcontainertype == containerType)
collationNeeded = targetCollation;
else
- collationNeeded = get_typcollation(arrayType);
+ collationNeeded = get_typcollation(containerType);
/* recurse to create appropriate RHS for container assign */
rhs = transformAssignmentIndirection(pstate,
NULL,
targetName,
true,
- typeNeeded,
- arrayTypMod,
+ sbsref->refassgntype,
+ sbsref->reftypmod,
collationNeeded,
next_indirection,
rhs,
location);
- /* process subscripts */
- result = (Node *) transformArraySubscripts(pstate,
- basenode,
- arrayType,
- elementTypeId,
- arrayTypMod,
- subscripts,
- rhs);
-
- /* If target was a domain over array, need to coerce up to the domain */
- if (arrayType != targetTypeId)
+ /* Provide fully prepared subscriptinng information for custom validation */
+ sbsref->refassgnexpr = (Expr *) rhs;
+ sbsroutines->validate(rhs != NULL, sbsref, pstate);
+
+ result = (Node *) sbsref;
+
+ /* If target was a domain over container, need to coerce up to the domain */
+ if (sbsref->refcontainertype != targetTypeId)
{
- Oid resulttype = exprType(result);
+ Oid resulttype = exprType(result);
result = coerce_to_target_type(pstate,
result, resulttype,
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index a1de680..6c98e48 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7772,17 +7772,17 @@ get_rule_expr(Node *node, deparse_context *context,
if (need_parens)
appendStringInfoChar(buf, ')');
- /*
- * If there's a refassgnexpr, we want to print the node in the
- * format "array[subscripts] := refassgnexpr". This is not
- * legal SQL, so decompilation of INSERT or UPDATE statements
- * should always use processIndirection as part of the
- * statement-level syntax. We should only see this when
- * EXPLAIN tries to print the targetlist of a plan resulting
- * from such a statement.
- */
- if (aref->refassgnexpr)
+ if (IsAssignment(sbsref))
{
+ /*
+ * If there's a refassgnexpr, we want to print the node in the
+ * format "container[subscripts] := refassgnexpr". This is not
+ * legal SQL, so decompilation of INSERT or UPDATE statements
+ * should always use processIndirection as part of the
+ * statement-level syntax. We should only see this when
+ * EXPLAIN tries to print the targetlist of a plan resulting
+ * from such a statement.
+ */
Node *refassgnexpr;
/*
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index bba595a..99c3a9e 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3106,3 +3106,26 @@ get_range_subtype(Oid rangeOid)
else
return InvalidOid;
}
+
+/*
+ * get_typsubshandler
+ *
+ * Given the type OID, return the type's subscripting procedures, if any,
+ * through pointers in arguments.
+ */
+RegProcedure
+get_typsubsprocs(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+ if (HeapTupleIsValid(tp))
+ {
+ RegProcedure handler = ((Form_pg_type) GETSTRUCT(tp))->typsubshandler;
+ ReleaseSysCache(tp);
+
+ return handler;
+ }
+ else
+ return InvalidOid;
+}
diff --git a/src/include/c.h b/src/include/c.h
index 1e50103..2ae0cdc 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -499,6 +499,8 @@ typedef struct
int indx[MAXDIM];
} IntArray;
+#define MAX_SUBSCRIPT_DEPTH 12
+
/* ----------------
* Variable-length datatypes all share the 'struct varlena' header.
*
diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat
index 9fffdef..f42cbfe 100644
--- a/src/include/catalog/pg_class.dat
+++ b/src/include/catalog/pg_class.dat
@@ -25,7 +25,7 @@
reloftype => '0', relowner => 'PGUID', relam => '0', relfilenode => '0',
reltablespace => '0', relpages => '0', reltuples => '0', relallvisible => '0',
reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
- relpersistence => 'p', relkind => 'r', relnatts => '30', relchecks => '0',
+ relpersistence => 'p', relkind => 'r', relnatts => '31', relchecks => '0',
relhasoids => 't', relhasrules => 'f', relhastriggers => 'f',
relhassubclass => 'f', relrowsecurity => 'f', relforcerowsecurity => 'f',
relispopulated => 't', relreplident => 'n', relispartition => 'f',
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 48e01cd..68f6d79 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -48,7 +48,8 @@
typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f',
typcategory => 'S', typelem => 'char', typarray => '_name',
typinput => 'namein', typoutput => 'nameout', typreceive => 'namerecv',
- typsend => 'namesend', typalign => 'c' },
+ typsend => 'namesend', typalign => 'c',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '20', descr => '~18 digit integer, 8-byte storage',
typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
typcategory => 'N', typarray => '_int8', typinput => 'int8in',
@@ -62,7 +63,8 @@
typname => 'int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int2', typarray => '_int2vector', typinput => 'int2vectorin',
typoutput => 'int2vectorout', typreceive => 'int2vectorrecv',
- typsend => 'int2vectorsend', typalign => 'i' },
+ typsend => 'int2vectorsend', typalign => 'i',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '23', descr => '-2 billion to 2 billion integer, 4-byte storage',
typname => 'int4', typlen => '4', typbyval => 't', typcategory => 'N',
typarray => '_int4', typinput => 'int4in', typoutput => 'int4out',
@@ -97,7 +99,8 @@
typname => 'oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'oid', typarray => '_oidvector', typinput => 'oidvectorin',
typoutput => 'oidvectorout', typreceive => 'oidvectorrecv',
- typsend => 'oidvectorsend', typalign => 'i' },
+ typsend => 'oidvectorsend', typalign => 'i',
+ typsubshandler => 'array_subscript_handler' },
# hand-built rowtype entries for bootstrapped catalogs
# NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations
@@ -138,12 +141,14 @@
typname => '_xml', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'xml', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '199',
typname => '_json', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'json', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '194', oid_symbol => 'PGNODETREEOID',
descr => 'string representing an internal node tree',
typname => 'pg_node_tree', typlen => '-1', typbyval => 'f',
@@ -185,37 +190,38 @@
typname => 'point', typlen => '16', typbyval => 'f', typcategory => 'G',
typelem => 'float8', typarray => '_point', typinput => 'point_in',
typoutput => 'point_out', typreceive => 'point_recv', typsend => 'point_send',
- typalign => 'd' },
+ typalign => 'd', typsubshandler => 'array_subscript_handler' },
{ oid => '601', descr => 'geometric line segment \'(pt1,pt2)\'',
typname => 'lseg', typlen => '32', typbyval => 'f', typcategory => 'G',
typelem => 'point', typarray => '_lseg', typinput => 'lseg_in',
typoutput => 'lseg_out', typreceive => 'lseg_recv', typsend => 'lseg_send',
- typalign => 'd' },
+ typalign => 'd', typsubshandler => 'array_subscript_handler' },
{ oid => '602', descr => 'geometric path \'(pt1,...)\'',
typname => 'path', typlen => '-1', typbyval => 'f', typcategory => 'G',
typarray => '_path', typinput => 'path_in', typoutput => 'path_out',
typreceive => 'path_recv', typsend => 'path_send', typalign => 'd',
- typstorage => 'x' },
+ typstorage => 'x', typsubshandler => 'array_subscript_handler' },
{ oid => '603', descr => 'geometric box \'(lower left,upper right)\'',
typname => 'box', typlen => '32', typbyval => 'f', typcategory => 'G',
typdelim => ';', typelem => 'point', typarray => '_box', typinput => 'box_in',
typoutput => 'box_out', typreceive => 'box_recv', typsend => 'box_send',
- typalign => 'd' },
+ typalign => 'd', typsubshandler => 'array_subscript_handler' },
{ oid => '604', descr => 'geometric polygon \'(pt1,...)\'',
typname => 'polygon', typlen => '-1', typbyval => 'f', typcategory => 'G',
typarray => '_polygon', typinput => 'poly_in', typoutput => 'poly_out',
typreceive => 'poly_recv', typsend => 'poly_send', typalign => 'd',
- typstorage => 'x' },
+ typstorage => 'x', typsubshandler => 'array_subscript_handler' },
{ oid => '628', descr => 'geometric line',
typname => 'line', typlen => '24', typbyval => 'f', typcategory => 'G',
typelem => 'float8', typarray => '_line', typinput => 'line_in',
typoutput => 'line_out', typreceive => 'line_recv', typsend => 'line_send',
- typalign => 'd' },
+ typalign => 'd', typsubshandler => 'array_subscript_handler' },
{ oid => '629',
typname => '_line', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'line', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# OIDS 700 - 799
@@ -258,7 +264,8 @@
typname => '_circle', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'circle', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '790', oid_symbol => 'CASHOID',
descr => 'monetary amounts, $d,ddd.cc',
typname => 'money', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
@@ -269,7 +276,8 @@
typname => '_money', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'money', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# OIDS 800 - 899
@@ -299,142 +307,166 @@
typname => '_bool', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'bool', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1001',
typname => '_bytea', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'bytea', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1002',
typname => '_char', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'char', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1003',
typname => '_name', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'name', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1005',
typname => '_int2', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int2', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1006',
typname => '_int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int2vector', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1007',
typname => '_int4', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int4', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1008',
typname => '_regproc', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'regproc', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1009',
typname => '_text', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'text', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
- typcollation => '100' },
+ typcollation => '100', typsubshandler => 'array_subscript_handler' },
{ oid => '1028',
typname => '_oid', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'oid', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1010',
typname => '_tid', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'tid', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1011',
typname => '_xid', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'xid', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1012',
typname => '_cid', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'cid', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1013',
typname => '_oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'oidvector', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1014',
typname => '_bpchar', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'bpchar', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'bpchartypmodin', typmodout => 'bpchartypmodout',
typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
- typcollation => '100' },
+ typcollation => '100', typsubshandler => 'array_subscript_handler' },
{ oid => '1015',
typname => '_varchar', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'varchar', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'varchartypmodin', typmodout => 'varchartypmodout',
typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
- typcollation => '100' },
+ typcollation => '100', typsubshandler => 'array_subscript_handler' },
{ oid => '1016',
typname => '_int8', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int8', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1017',
typname => '_point', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'point', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1018',
typname => '_lseg', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'lseg', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1019',
typname => '_path', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'path', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1020',
typname => '_box', typlen => '-1', typbyval => 'f', typcategory => 'A',
typdelim => ';', typelem => 'box', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1021',
typname => '_float4', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'float4', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1022',
typname => '_float8', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'float8', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1023',
typname => '_abstime', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'abstime', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1024',
typname => '_reltime', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'reltime', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1025',
typname => '_tinterval', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'tinterval', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1027',
typname => '_polygon', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'polygon', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1033', descr => 'access control list',
typname => 'aclitem', typlen => '12', typbyval => 'f', typcategory => 'U',
typarray => '_aclitem', typinput => 'aclitemin', typoutput => 'aclitemout',
@@ -443,32 +475,38 @@
typname => '_aclitem', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'aclitem', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1040',
typname => '_macaddr', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'macaddr', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '775',
typname => '_macaddr8', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'macaddr8', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1041',
typname => '_inet', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'inet', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '651',
typname => '_cidr', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'cidr', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1263',
typname => '_cstring', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'cstring', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1042',
descr => 'char(length), blank-padded string, fixed storage length',
typname => 'bpchar', typlen => '-1', typbyval => 'f', typcategory => 'S',
@@ -506,18 +544,21 @@
typelem => 'timestamp', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'timestamptypmodin', typmodout => 'timestamptypmodout',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1182',
typname => '_date', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'date', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1183',
typname => '_time', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'time', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'timetypmodin', typmodout => 'timetypmodout',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1184', descr => 'date and time with time zone',
typname => 'timestamptz', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
typcategory => 'D', typispreferred => 't', typarray => '_timestamptz',
@@ -530,7 +571,8 @@
typcategory => 'A', typelem => 'timestamptz', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'timestamptztypmodin', typmodout => 'timestamptztypmodout',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1186', descr => '@ <number> <units>, time interval',
typname => 'interval', typlen => '16', typbyval => 'f', typcategory => 'T',
typispreferred => 't', typarray => '_interval', typinput => 'interval_in',
@@ -542,7 +584,8 @@
typelem => 'interval', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'intervaltypmodin', typmodout => 'intervaltypmodout',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# OIDS 1200 - 1299
@@ -551,7 +594,8 @@
typelem => 'numeric', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'numerictypmodin', typmodout => 'numerictypmodout',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1266', descr => 'time of day with time zone',
typname => 'timetz', typlen => '12', typbyval => 'f', typcategory => 'D',
typarray => '_timetz', typinput => 'timetz_in', typoutput => 'timetz_out',
@@ -563,7 +607,8 @@
typelem => 'timetz', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'timetztypmodin', typmodout => 'timetztypmodout',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# OIDS 1500 - 1599
@@ -577,7 +622,8 @@
typelem => 'bit', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'bittypmodin', typmodout => 'bittypmodout',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '1562', descr => 'variable-length bit string',
typname => 'varbit', typlen => '-1', typbyval => 'f', typcategory => 'V',
typispreferred => 't', typarray => '_varbit', typinput => 'varbit_in',
@@ -589,7 +635,8 @@
typelem => 'varbit', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
typmodin => 'varbittypmodin', typmodout => 'varbittypmodout',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# OIDS 1700 - 1799
@@ -613,7 +660,8 @@
typname => '_refcursor', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'refcursor', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2202', descr => 'registered procedure (with args)',
typname => 'regprocedure', typlen => '4', typbyval => 't', typcategory => 'N',
@@ -650,37 +698,44 @@
typname => '_regprocedure', typlen => '-1', typbyval => 'f',
typcategory => 'A', typelem => 'regprocedure', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2208',
typname => '_regoper', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'regoper', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2209',
typname => '_regoperator', typlen => '-1', typbyval => 'f',
typcategory => 'A', typelem => 'regoperator', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2210',
typname => '_regclass', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'regclass', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2211',
typname => '_regtype', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'regtype', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '4097',
typname => '_regrole', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'regrole', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '4090',
typname => '_regnamespace', typlen => '-1', typbyval => 'f',
typcategory => 'A', typelem => 'regnamespace', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# uuid
{ oid => '2950', descr => 'UUID datatype',
@@ -691,7 +746,8 @@
typname => '_uuid', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'uuid', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# pg_lsn
{ oid => '3220', oid_symbol => 'LSNOID', descr => 'PostgreSQL LSN datatype',
@@ -703,7 +759,8 @@
typname => '_pg_lsn', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'pg_lsn', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# text search
{ oid => '3614', descr => 'text representation for text search',
@@ -737,39 +794,45 @@
typname => '_tsvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'tsvector', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3644',
typname => '_gtsvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'gtsvector', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3645',
typname => '_tsquery', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'tsquery', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3735',
typname => '_regconfig', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'regconfig', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3770',
typname => '_regdictionary', typlen => '-1', typbyval => 'f',
typcategory => 'A', typelem => 'regdictionary', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# jsonb
{ oid => '3802', descr => 'Binary JSON',
typname => 'jsonb', typlen => '-1', typbyval => 'f', typcategory => 'U',
typarray => '_jsonb', typinput => 'jsonb_in', typoutput => 'jsonb_out',
typreceive => 'jsonb_recv', typsend => 'jsonb_send', typalign => 'i',
- typstorage => 'x' },
+ typstorage => 'x', typsubshandler => 'jsonb_subscript_handler' },
{ oid => '3807',
typname => '_jsonb', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'jsonb', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2970', descr => 'txid snapshot',
typname => 'txid_snapshot', typlen => '-1', typbyval => 'f',
@@ -781,7 +844,8 @@
typname => '_txid_snapshot', typlen => '-1', typbyval => 'f',
typcategory => 'A', typelem => 'txid_snapshot', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# range types
{ oid => '3904', descr => 'range of integers',
@@ -793,7 +857,8 @@
typname => '_int4range', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int4range', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3906', descr => 'range of numerics',
typname => 'numrange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typarray => '_numrange', typinput => 'range_in',
@@ -803,7 +868,8 @@
typname => '_numrange', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'numrange', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3908', descr => 'range of timestamps without time zone',
typname => 'tsrange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typarray => '_tsrange', typinput => 'range_in',
@@ -813,7 +879,8 @@
typname => '_tsrange', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'tsrange', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3910', descr => 'range of timestamps with time zone',
typname => 'tstzrange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typarray => '_tstzrange', typinput => 'range_in',
@@ -823,7 +890,8 @@
typname => '_tstzrange', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'tstzrange', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3912', descr => 'range of dates',
typname => 'daterange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typarray => '_daterange', typinput => 'range_in',
@@ -833,7 +901,8 @@
typname => '_daterange', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'daterange', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '3926', descr => 'range of bigints',
typname => 'int8range', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typarray => '_int8range', typinput => 'range_in',
@@ -843,7 +912,8 @@
typname => '_int8range', typlen => '-1', typbyval => 'f', typcategory => 'A',
typelem => 'int8range', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
# pseudo-types
# types with typtype='p' represent various special cases in the type system.
@@ -863,7 +933,8 @@
typname => '_record', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typelem => 'record', typinput => 'array_in',
typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+ typsubshandler => 'array_subscript_handler' },
{ oid => '2275',
typname => 'cstring', typlen => '-2', typbyval => 'f', typtype => 'p',
typcategory => 'P', typarray => '_cstring', typinput => 'cstring_in',
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 1e9cea7..5b442b6 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -214,6 +214,12 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
*/
Oid typcollation BKI_DEFAULT(0);
+ /*
+ * Type specific subscripting logic. If typsubshandler is none, it means
+ * that this type doesn't support subscripting.
+ */
+ regproc typsubshandler BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/*
@@ -321,7 +327,8 @@ extern ObjectAddress TypeCreate(Oid newTypeOid,
int32 typeMod,
int32 typNDims,
bool typeNotNull,
- Oid typeCollation);
+ Oid typeCollation,
+ Oid subscriptingParseProcedure);
extern void GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
@@ -339,6 +346,7 @@ extern void GenerateTypeDependencies(Oid typeNamespace,
bool isImplicitArray,
Oid baseType,
Oid typeCollation,
+ Oid subscriptingParseProcedure,
Node *defaultExpr,
bool rebuild);
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 58ae64b..f643e87 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -19,7 +19,7 @@
/* forward references to avoid circularity */
struct ExprEvalStep;
-struct ArrayRefState;
+struct SubscriptRoutines;
/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
/* expression's interpreter has been initialized */
@@ -639,28 +639,27 @@ typedef struct ExprEvalStep
} d;
} ExprEvalStep;
-
-/* Non-inline data for array operations */
-typedef struct ArrayRefState
+/* Non-inline data for container operations */
+typedef struct SubscriptingRefState
{
bool isassignment; /* is it assignment, or just fetch? */
- Oid refelemtype; /* OID of the array element type */
- int16 refattrlength; /* typlen of array type */
- int16 refelemlength; /* typlen of the array element type */
+ Oid refelemtype; /* OID of the container element type */
+ int16 refattrlength; /* typlen of container type */
+ int16 refelemlength; /* typlen of the container element type */
bool refelembyval; /* is the element type pass-by-value? */
char refelemalign; /* typalign of the element type */
/* numupper and upperprovided[] are filled at compile time */
/* at runtime, extracted subscript datums get stored in upperindex[] */
int numupper;
- bool upperprovided[MAXDIM];
- int upperindex[MAXDIM];
+ bool upperprovided[MAX_SUBSCRIPT_DEPTH];
+ Datum upperindex[MAX_SUBSCRIPT_DEPTH];
/* similarly for lower indexes, if any */
int numlower;
- bool lowerprovided[MAXDIM];
- int lowerindex[MAXDIM];
+ bool lowerprovided[MAX_SUBSCRIPT_DEPTH];
+ Datum lowerindex[MAX_SUBSCRIPT_DEPTH];
/* subscript expressions get evaluated into here */
Datum subscriptvalue;
@@ -670,11 +669,13 @@ typedef struct ArrayRefState
Datum replacevalue;
bool replacenull;
- /* if we have a nested assignment, ARRAYREF_OLD puts old value here */
+ /* if we have a nested assignment, SBSREF_OLD puts old value here */
Datum prevvalue;
bool prevnull;
-} ArrayRefState;
+ bool resnull;
+ struct SubscriptRoutines *sbsroutines;
+} SubscriptingRefState;
/* functions in execExpr.c */
extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 93719ad..22bed11 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -365,18 +365,18 @@ typedef struct WindowFunc
} WindowFunc;
/* ----------------
- * ArrayRef: describes an array subscripting operation
- *
- * An ArrayRef can describe fetching a single element from an array,
- * fetching a subarray (array slice), storing a single element into
- * an array, or storing a slice. The "store" cases work with an
- * initial array value and a source value that is inserted into the
- * appropriate part of the array; the result of the operation is an
- * entire new modified array value.
- *
- * If reflowerindexpr = NIL, then we are fetching or storing a single array
- * element at the subscripts given by refupperindexpr. Otherwise we are
- * fetching or storing an array slice, that is a rectangular subarray
+ * SubscriptingRef: describes a subscripting operation over a container
+ *
+ * A SubscriptingRef can describe fetching a single element from a container,
+ * fetching a part of container (e.g. array slice), storing a single element into
+ * a container, or storing a slice. The "store" cases work with an
+ * initial container value and a source value that is inserted into the
+ * appropriate part of the container; the result of the operation is an
+ * entire new modified container value.
+ *
+ * If reflowerindexpr = NIL, then we are fetching or storing a single container
+ * element at the subscripts given by refupperindexpr. Otherwise we are
+ * fetching or storing a container slice, that is a rectangular subcontainer
* with lower and upper bounds given by the index expressions.
* reflowerindexpr must be the same length as refupperindexpr when it
* is not NIL.
@@ -388,28 +388,35 @@ typedef struct WindowFunc
* element; but it is the array type when doing subarray fetch or either
* type of store.
*
- * Note: for the cases where an array is returned, if refexpr yields a R/W
- * expanded array, then the implementation is allowed to modify that object
+ * Note: for the cases where a container is returned, if refexpr yields a R/W
+ * expanded container, then the implementation is allowed to modify that object
* in-place and return the same object.)
* ----------------
*/
-typedef struct ArrayRef
+
+typedef struct SubscriptingRef
{
Expr xpr;
- Oid refarraytype; /* type of the array proper */
- Oid refelemtype; /* type of the array elements */
- int32 reftypmod; /* typmod of the array (and elements too) */
- Oid refcollid; /* OID of collation, or InvalidOid if none */
- List *refupperindexpr; /* expressions that evaluate to upper
- * array indexes */
- List *reflowerindexpr; /* expressions that evaluate to lower
- * array indexes, or NIL for single array
- * element */
- Expr *refexpr; /* the expression that evaluates to an array
- * value */
- Expr *refassgnexpr; /* expression for the source value, or NULL if
- * fetch */
-} ArrayRef;
+ Oid refcontainertype; /* type of the container proper */
+ Oid refelemtype; /* type of the container elements */
+ Oid refassgntype; /* type of assignment expr that is required */
+ int32 reftypmod; /* typmod of the container (and elements too) */
+ Oid refcollid; /* OID of collation, or InvalidOid if none */
+ Oid refnestedfunc; /* OID of type-specific function to handle nested assignment */
+ List *refupperindexpr; /* expressions that evaluate to upper container
+ * indexes */
+ List *reflowerindexpr; /* expressions that evaluate to lower container
+ * indexes, or NIL for single container element */
+ List *refindexprslice; /* whether or not related indexpr from
+ * reflowerindexpr is a slice */
+ Expr *refexpr; /* the expression that evaluates to a container
+ * value */
+
+ Expr *refassgnexpr; /* expression for the source value, or NULL if
+ * fetch */
+} SubscriptingRef;
+
+#define IsAssignment(expr) ( ((SubscriptingRef*) expr)->refassgnexpr != NULL )
/*
* CoercionContext - distinguishes the allowed set of type casts
diff --git a/src/include/nodes/subscripting.h b/src/include/nodes/subscripting.h
new file mode 100644
index 0000000..1800d5e
--- /dev/null
+++ b/src/include/nodes/subscripting.h
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+ *
+ * subscripting.h
+ * API for generic type subscripting
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/subscripting.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SUBSCRIPTING_H
+#define SUBSCRIPTING_H
+
+#include "parser/parse_node.h"
+#include "nodes/primnodes.h"
+
+struct ParseState;
+struct SubscriptingRefState;
+
+/* Callback function signatures --- see xsubscripting.sgml for more info. */
+typedef SubscriptingRef * (*SubscriptingPrepare) (bool isAssignment, SubscriptingRef *sbsef);
+
+typedef SubscriptingRef * (*SubscriptingValidate) (bool isAssignment, SubscriptingRef *sbsef,
+ struct ParseState *pstate);
+
+typedef Datum (*SubscriptingFetch) (Datum source, struct SubscriptingRefState *sbsrefstate);
+
+typedef Datum (*SubscriptingAssign) (Datum source, struct SubscriptingRefState *sbrsefstate);
+
+typedef struct SubscriptRoutines
+{
+ SubscriptingPrepare prepare;
+ SubscriptingValidate validate;
+ SubscriptingFetch fetch;
+ SubscriptingAssign assign;
+
+} SubscriptRoutines;
+
+
+#endif /* SUBSCRIPTING_H */
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 0230543..62298d9 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -15,6 +15,7 @@
#define PARSE_NODE_H
#include "nodes/parsenodes.h"
+#include "nodes/subscripting.h"
#include "utils/queryenvironment.h"
#include "utils/relcache.h"
@@ -271,14 +272,16 @@ extern void cancel_parser_errposition_callback(ParseCallbackState *pcbstate);
extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno,
int location);
-extern Oid transformArrayType(Oid *arrayType, int32 *arrayTypmod);
-extern ArrayRef *transformArraySubscripts(ParseState *pstate,
- Node *arrayBase,
- Oid arrayType,
- Oid elementType,
- int32 arrayTypMod,
- List *indirection,
- Node *assignFrom);
+extern void transformContainerType(Oid *containerType, int32 *containerTypmod);
+
+extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate,
+ Node *containerBase,
+ Oid containerType,
+ Oid elementType,
+ int32 containerTypMod,
+ List *indirection,
+ Node *assignFrom);
+extern SubscriptRoutines* getSubscriptingRoutines(Oid containerType);
extern Const *make_const(ParseState *pstate, Value *value, int location);
#endif /* PARSE_NODE_H */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index e55ea40..6e021c4 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -176,6 +176,7 @@ extern void free_attstatsslot(AttStatsSlot *sslot);
extern char *get_namespace_name(Oid nspid);
extern char *get_namespace_name_or_temp(Oid nspid);
extern Oid get_range_subtype(Oid rangeOid);
+extern RegProcedure get_typsubsprocs(Oid typid);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
/* type_is_array_domain accepts both plain arrays and domains over arrays */
--
2.7.4