generic_type_subscription_v13.patch
text/x-patch
Filename: generic_type_subscription_v13.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v13
| File | + | − |
|---|---|---|
| contrib/pg_stat_statements/pg_stat_statements.c | 9 | 7 |
| contrib/postgres_fdw/deparse.c | 6 | 6 |
| doc/src/sgml/catalogs.sgml | 7 | 0 |
| doc/src/sgml/extend.sgml | 6 | 0 |
| doc/src/sgml/filelist.sgml | 1 | 0 |
| doc/src/sgml/json.sgml | 25 | 0 |
| doc/src/sgml/ref/create_type.sgml | 29 | 1 |
| doc/src/sgml/xsubscripting.sgml | 102 | 0 |
| src/backend/catalog/dependency.c | 8 | 0 |
| src/backend/catalog/heap.c | 4 | 2 |
| src/backend/catalog/pg_type.c | 15 | 1 |
| src/backend/commands/typecmds.c | 58 | 7 |
| src/backend/executor/execExpr.c | 79 | 47 |
| src/backend/executor/execExprInterp.c | 51 | 133 |
| src/backend/nodes/copyfuncs.c | 9 | 7 |
| src/backend/nodes/equalfuncs.c | 6 | 4 |
| src/backend/nodes/nodeFuncs.c | 40 | 27 |
| src/backend/nodes/outfuncs.c | 7 | 5 |
| src/backend/nodes/readfuncs.c | 9 | 7 |
| src/backend/optimizer/path/costsize.c | 5 | 0 |
| src/backend/optimizer/plan/setrefs.c | 5 | 0 |
| src/backend/optimizer/util/clauses.c | 4 | 6 |
| src/backend/parser/analyze.c | 3 | 6 |
| src/backend/parser/parse_expr.c | 14 | 14 |
| src/backend/parser/parse_node.c | 87 | 144 |
| src/backend/parser/parse_target.c | 35 | 52 |
| src/backend/rewrite/rewriteHandler.c | 14 | 14 |
| src/backend/utils/adt/arrayfuncs.c | 278 | 1 |
| src/backend/utils/adt/jsonb.c | 19 | 8 |
| src/backend/utils/adt/jsonb_util.c | 66 | 10 |
| src/backend/utils/adt/jsonfuncs.c | 233 | 94 |
| src/backend/utils/adt/ruleutils.c | 40 | 44 |
| src/backend/utils/cache/lsyscache.c | 20 | 0 |
| src/include/catalog/pg_class.h | 1 | 1 |
| src/include/catalog/pg_proc.h | 15 | 0 |
| src/include/catalog/pg_type_fn.h | 3 | 1 |
| src/include/catalog/pg_type.h | 178 | 172 |
| src/include/c.h | 2 | 0 |
| src/include/executor/execExpr.h | 29 | 27 |
| src/include/nodes/execnodes.h | 0 | 1 |
| src/include/nodes/nodes.h | 1 | 1 |
| src/include/nodes/primnodes.h | 37 | 29 |
| src/include/parser/parse_node.h | 6 | 5 |
| src/include/utils/jsonb.h | 2 | 0 |
| src/include/utils/lsyscache.h | 1 | 0 |
| src/pl/plpgsql/src/pl_exec.c | 3 | 3 |
| src/test/regress/expected/arrays.out | 3 | 3 |
| src/test/regress/expected/jsonb.out | 208 | 0 |
| src/test/regress/sql/arrays.sql | 2 | 2 |
| src/test/regress/sql/jsonb.sql | 59 | 0 |
| src/tutorial/Makefile | 2 | 2 |
| src/tutorial/subscripting.c | 172 | 0 |
| src/tutorial/subscripting.source | 81 | 0 |
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index bf03e67..332a5ce 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2530,14 +2530,16 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) expr->aggfilter);
}
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *aref = (ArrayRef *) node;
-
- JumbleExpr(jstate, (Node *) aref->refupperindexpr);
- JumbleExpr(jstate, (Node *) aref->reflowerindexpr);
- JumbleExpr(jstate, (Node *) aref->refexpr);
- JumbleExpr(jstate, (Node *) aref->refassgnexpr);
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
+
+ JumbleExpr(jstate, (Node *) sbsref->refupperindexpr);
+ JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
+ JumbleExpr(jstate, (Node *) sbsref->refexpr);
+ JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
+ APP_JUMB(sbsref->refevalfunc);
+ APP_JUMB(sbsref->refnestedfunc);
}
break;
case T_FuncExpr:
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 1d5aa83..83e21f5 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -147,7 +147,7 @@ static void deparseExpr(Expr *expr, deparse_expr_cxt *context);
static void deparseVar(Var *node, deparse_expr_cxt *context);
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype);
static void deparseParam(Param *node, deparse_expr_cxt *context);
-static void deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context);
+static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context);
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform);
@@ -398,9 +398,9 @@ foreign_expr_walker(Node *node,
state = FDW_COLLATE_UNSAFE;
}
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *ar = (ArrayRef *) node;
+ SubscriptingRef *ar = (SubscriptingRef *) node;
/* Assignment should not be in restrictions. */
if (ar->refassgnexpr != NULL)
@@ -2132,8 +2132,8 @@ deparseExpr(Expr *node, deparse_expr_cxt *context)
case T_Param:
deparseParam((Param *) node, context);
break;
- case T_ArrayRef:
- deparseArrayRef((ArrayRef *) node, context);
+ case T_SubscriptingRef:
+ deparseSubscriptingRef((SubscriptingRef *) node, context);
break;
case T_FuncExpr:
deparseFuncExpr((FuncExpr *) node, context);
@@ -2382,7 +2382,7 @@ deparseParam(Param *node, deparse_expr_cxt *context)
* Deparse an array subscript expression.
*/
static void
-deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context)
+deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
{
StringInfo buf = context->buf;
ListCell *lowlist_item;
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index aa5e705..960062f 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7793,6 +7793,13 @@ SCRAM-SHA-256$<replaceable><iteration count></>:<replaceable><salt><
</row>
<row>
+ <entry><structfield>typsubsparse</structfield></entry>
+ <entry><type>regproc</type></entry>
+ <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
+ <entry>Custom subscripting function with type-specific logic, or 0 if this type doesn't support subscripting.</entry>
+ </row>
+
+ <row>
<entry><structfield>typdefaultbin</structfield></entry>
<entry><type>pg_node_tree</type></entry>
<entry></entry>
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index c4f211b..5b77da4 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -35,6 +35,11 @@
</listitem>
<listitem>
<para>
+ subscripting procedure (starting in <xref linkend="xsubscripting">)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
operator classes for indexes (starting in <xref linkend="xindex">)
</para>
</listitem>
@@ -283,6 +288,7 @@
&xaggr;
&xtypes;
&xoper;
+ &xsubscripting;
&xindex;
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 2ec83af..417c0a5 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -72,6 +72,7 @@
<!ENTITY xplang SYSTEM "xplang.sgml">
<!ENTITY xoper SYSTEM "xoper.sgml">
<!ENTITY xtypes SYSTEM "xtypes.sgml">
+<!ENTITY xsubscripting SYSTEM "xsubscripting.sgml">
<!ENTITY plperl SYSTEM "plperl.sgml">
<!ENTITY plpython SYSTEM "plpython.sgml">
<!ENTITY plsql SYSTEM "plpgsql.sgml">
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index 3cf78d6..6dc46ac 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -569,4 +569,29 @@ SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qu
compared using the default database collation.
</para>
</sect2>
+
+ <sect2 id="jsonb-subscripting">
+ <title><type>jsonb</> Subscripting</title>
+ <para>
+ <type>jsonb</> data type supports array-style subscripting expressions to extract or update particular element. An example of subscripting syntax:
+<programlisting>
+-- Extract value by key
+SELECT ('{"a": 1}'::jsonb)['a'];
+
+-- Extract nested value by key path
+SELECT ('{"a": {"b": {"c": 1}}}'::jsonb)['a']['b']['c'];
+
+-- Extract element by index
+SELECT ('[1, "2", null]'::jsonb)['1'];
+
+-- Update value by key
+UPDATE table_name set jsonb_field['key'] = 1;
+
+-- Select records using where clause with subscripting
+SELECT * from table_name where jsonb_field['key'] = '"value"';
+</programlisting>
+ </para>
+ </sect2>
+
+
</sect1>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 7146c4a..c3df0f9 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -54,6 +54,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
[ , ELEMENT = <replaceable class="parameter">element</replaceable> ]
[ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
[ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
+ [ , SUBSCRIPTING = <replaceable class="parameter">subscripting_function</replaceable> ]
)
CREATE TYPE <replaceable class="parameter">name</replaceable>
@@ -194,7 +195,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<replaceable class="parameter">send_function</replaceable>,
<replaceable class="parameter">type_modifier_input_function</replaceable>,
<replaceable class="parameter">type_modifier_output_function</replaceable> and
- <replaceable class="parameter">analyze_function</replaceable>
+ <replaceable class="parameter">analyze_function</replaceable>,
+ <replaceable class="parameter">subscripting_function</replaceable>
are optional. Generally these functions have to be coded in C
or another low-level language.
</para>
@@ -451,6 +453,22 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
make use of the collation information; this does not happen
automatically merely by marking the type collatable.
</para>
+
+ <para>
+ The optional
+ <replaceable class="parameter">subscripting_function</replaceable>
+ contains type-specific logic for subscripting of the data type.
+ By default, there is no such function, which means that the data
+ type doesn't support subscripting. The subscripting function must be
+ declared to take a single argument of type <type>internal</>, and return
+ a <type>internal</> result. There are two examples of implementation for
+ subscripting function in case of array
+ (<replaceable class="parameter">array_subscripting</replaceable>)
+ and jsonb
+ (<replaceable class="parameter">jsonb_subscripting</replaceable>)
+ types in <filename>src/backend/utils/adt/arrayfuncs.c</> and
+ <filename>src/backend/utils/adt/jsonfuncs.c</> corresponding.
+ </para>
</refsect2>
<refsect2>
@@ -766,6 +784,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">subscripting_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of a function that contains type-specific subscripting logic for
+ the data type.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/doc/src/sgml/xsubscripting.sgml b/doc/src/sgml/xsubscripting.sgml
new file mode 100644
index 0000000..b5e909b
--- /dev/null
+++ b/doc/src/sgml/xsubscripting.sgml
@@ -0,0 +1,102 @@
+<!-- doc/src/sgml/xsubscripting.sgml -->
+
+ <sect1 id="xsubscripting">
+ <title>User-defined subscripting procedure</title>
+
+ <indexterm zone="xsubscripting">
+ <primary>custom subscripting</primary>
+ </indexterm>
+ <para>
+ When you define a new base type, you can also specify a custom procedure
+ to handle subscripting expressions. It should contain logic for verification
+ and decide which function must be used for evaluation of this expression.
+ For instance:
+</para>
+<programlisting><![CDATA[
+typedef struct Custom
+{
+ int first;
+ int second;
+} Custom;
+
+Datum
+custom_subscripting_extract(PG_FUNCTION_ARGS)
+{
+ Custom *result = (Custom *) sbsdata->containerSource;
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+
+ // Some assign logic based on sbsdata
+}
+
+Datum
+custom_subscripting_assign(PG_FUNCTION_ARGS)
+{
+ Custom *containerSource = (Custom *) PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+
+ // Some extraction logic based on sbsdata
+}
+
+PG_FUNCTION_INFO_V1(custom_subscripting);
+
+Datum
+custom_subscript_parse(PG_FUNCTION_ARGS)
+{
+ bool isAssignment = PG_GETARG_BOOL(0);
+ SubscriptingRef *sbsref = (SubscriptingRef *) PG_GETARG_POINTER(0);
+ Datum assign_proc = CStringGetTextDatum("custom_subscripting_assign");
+ Datum extract_proc = CStringGetTextDatum("custom_subscripting_extract");
+
+ // Some verifications or type coersion
+
+ if (isAssignment)
+ sbsref->refevalfunc = DirectFunctionCall1(to_regproc, assign_proc);
+ else
+ sbsref->refevalfunc = DirectFunctionCall1(to_regproc, extract_proc);
+
+ PG_RETURN_POINTER(sbsref);
+}]]>
+</programlisting>
+
+<para>
+ Then you can define a subscripting procedure and a custom data type:
+</para>
+<programlisting>
+CREATE FUNCTION custom_subscript_parse(internal)
+ RETURNS internal
+ AS '<replaceable>filename</replaceable>'
+ LANGUAGE C IMMUTABLE STRICT;
+
+CREATE TYPE custom (
+ internallength = 4,
+ input = custom_in,
+ output = custom_out,
+ subscripting = custom_subscript_parse
+);
+</programlisting>
+
+<para>
+ and use it as usual:
+</para>
+<programlisting>
+CREATE TABLE test_subscripting (
+ data custom
+);
+
+INSERT INTO test_subscripting VALUES ('(1, 2)');
+
+SELECT data[0] from test_subscripting;
+
+UPDATE test_subscripting SET data[1] = 3;
+</programlisting>
+
+
+ <para>
+ The examples of custom subscripting implementation can be found in
+ <filename>subscripting.sql</filename> and <filename>subscripting.c</filename>
+ in the <filename>src/tutorial</> directory of the source distribution.
+ See the <filename>README</> file in that directory for instructions
+ about running the examples.
+ </para>
+
+</sect1>
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index cdf4535..b62cceb 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1647,6 +1647,14 @@ find_expr_references_walker(Node *node,
context->addrs);
/* fall through to examine arguments */
}
+ else if (IsA(node, SubscriptingRef))
+ {
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
+
+ add_object_address(OCLASS_PROC, sbsref->refevalfunc, 0,
+ context->addrs);
+ /* fall through to examine arguments */
+ }
else if (IsA(node, OpExpr))
{
OpExpr *opexpr = (OpExpr *) node;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index ab3d83f..7970203 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -979,7 +979,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); /* typsubsparse - none */
}
/* --------------------------------
@@ -1249,7 +1250,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_PARSE); /* array implementation */
pfree(relarrayname);
}
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 04c10c6..65e9063 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -118,6 +118,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_typsubsparse - 1] = ObjectIdGetDatum(InvalidOid);
nulls[Anum_pg_type_typdefaultbin - 1] = true;
nulls[Anum_pg_type_typdefault - 1] = true;
nulls[Anum_pg_type_typacl - 1] = true;
@@ -164,6 +165,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
false,
InvalidOid,
InvalidOid,
+ InvalidOid,
NULL,
false);
@@ -222,7 +224,8 @@ TypeCreate(Oid newTypeOid,
int32 typeMod,
int32 typNDims, /* Array dimensions for baseType */
bool typeNotNull,
- Oid typeCollation)
+ Oid typeCollation,
+ Oid subscriptingProcedure)
{
Relation pg_type_desc;
Oid typeObjectId;
@@ -362,6 +365,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_typsubsparse - 1] = ObjectIdGetDatum(subscriptingProcedure);
/*
* initialize the default binary value for this type. Check for nulls of
@@ -479,6 +483,7 @@ TypeCreate(Oid newTypeOid,
isImplicitArray,
baseType,
typeCollation,
+ subscriptingProcedure,
(defaultTypeBin ?
stringToNode(defaultTypeBin) :
NULL),
@@ -525,6 +530,7 @@ GenerateTypeDependencies(Oid typeNamespace,
bool isImplicitArray,
Oid baseType,
Oid typeCollation,
+ Oid subscriptingProcedure,
Node *defaultExpr,
bool rebuild)
{
@@ -677,6 +683,14 @@ GenerateTypeDependencies(Oid typeNamespace,
/* Normal dependency on the default expression. */
if (defaultExpr)
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
+ if (OidIsValid(subscriptingProcedure))
+ {
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = subscriptingProcedure;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
}
/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index c765e97..430dcfc 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -94,6 +94,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);
static Oid findRangeSubOpclass(List *opcname, Oid subtype);
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
@@ -125,6 +126,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
List *typmodinName = NIL;
List *typmodoutName = NIL;
List *analyzeName = NIL;
+ List *subscriptingName = NIL;
char category = TYPCATEGORY_USER;
bool preferred = false;
char delimiter = DEFAULT_TYPDELIM;
@@ -143,6 +145,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *typmodinNameEl = NULL;
DefElem *typmodoutNameEl = NULL;
DefElem *analyzeNameEl = NULL;
+ DefElem *subscriptingNameEl = NULL;
DefElem *categoryEl = NULL;
DefElem *preferredEl = NULL;
DefElem *delimiterEl = NULL;
@@ -165,6 +168,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
Oid resulttype;
ListCell *pl;
ObjectAddress address;
+ Oid subscriptingOid = InvalidOid;
/*
* As of Postgres 8.4, we require superuser privilege to create a base
@@ -264,6 +268,9 @@ DefineType(ParseState *pstate, List *names, List *parameters)
else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
pg_strcasecmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
+ else if (pg_strcasecmp(defel->defname, "subscripting") == 0 ||
+ pg_strcasecmp(defel->defname, "subscripting") == 0)
+ defelp = &subscriptingNameEl;
else if (pg_strcasecmp(defel->defname, "category") == 0)
defelp = &categoryEl;
else if (pg_strcasecmp(defel->defname, "preferred") == 0)
@@ -334,6 +341,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
typmodoutName = defGetQualifiedName(typmodoutNameEl);
if (analyzeNameEl)
analyzeName = defGetQualifiedName(analyzeNameEl);
+ if (subscriptingNameEl)
+ subscriptingName = defGetQualifiedName(subscriptingNameEl);
if (categoryEl)
{
char *p = defGetString(categoryEl);
@@ -515,6 +524,9 @@ DefineType(ParseState *pstate, List *names, List *parameters)
if (analyzeName)
analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
+ if (subscriptingName)
+ subscriptingOid = findTypeSubscriptingFunction(subscriptingName);
+
/*
* Check permissions on functions. We choose to require the creator/owner
* of a type to also own the underlying functions. Since creating a type
@@ -634,7 +646,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 */
+ subscriptingOid); /* subscripting procedure */
Assert(typoid == address.objectId);
/*
@@ -675,7 +688,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_PARSE);
pfree(array_type);
@@ -737,6 +751,7 @@ DefineDomain(CreateDomainStmt *stmt)
Oid receiveProcedure;
Oid sendProcedure;
Oid analyzeProcedure;
+ Oid subscriptingProcedure;
bool byValue;
char category;
char delimiter;
@@ -860,6 +875,9 @@ DefineDomain(CreateDomainStmt *stmt)
/* Analysis function */
analyzeProcedure = baseType->typanalyze;
+ /* Subscripting function */
+ subscriptingProcedure = baseType->typsubsparse;
+
/* Inherited default value */
datum = SysCacheGetAttr(TYPEOID, typeTup,
Anum_pg_type_typdefault, &isnull);
@@ -1061,7 +1079,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 */
+ subscriptingProcedure); /* subscripting procedure */
/*
* Process constraints which refer to the domain ID returned by TypeCreate
@@ -1173,7 +1192,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); /* typsubsparse - none */
/* Enter the enum's values into pg_enum */
EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
@@ -1213,7 +1233,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_PARSE); /* array subscripting implementation */
pfree(enumArrayName);
@@ -1501,7 +1522,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); /* typsubsparse - none */
Assert(typoid == address.objectId);
/* Create the entry in pg_range */
@@ -1543,7 +1565,8 @@ DefineRange(CreateRangeStmt *stmt)
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */
- InvalidOid); /* typcollation */
+ InvalidOid, /* typcollation */
+ F_ARRAY_SUBSCRIPT_PARSE); /* array subscripting implementation */
pfree(rangeArrayName);
@@ -1887,6 +1910,33 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
return procOid;
}
+static Oid
+findTypeSubscriptingFunction(List *procname)
+{
+ Oid argList[1];
+ Oid procOid;
+
+ /*
+ * Subscripting functions always take one INTERNAL argument and return INTERNAL.
+ */
+ argList[0] = INTERNALOID;
+
+ procOid = LookupFuncName(procname, 1, argList, true);
+ if (!OidIsValid(procOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, 1, NIL, argList))));
+
+ if (get_func_rettype(procOid) != INTERNALOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("type subscripting function %s must return type %s",
+ NameListToString(procname), "internal")));
+
+ return procOid;
+}
+
/*
* Find suitable support functions and opclasses for a range type.
*/
@@ -2240,6 +2290,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
false, /* a domain isn't an implicit array */
typTup->typbasetype,
typTup->typcollation,
+ typTup->typsubsparse,
defaultExpr,
true); /* Rebuild is true */
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 5a34a46..54e21e1 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -65,7 +65,7 @@ static void ExecInitExprSlots(ExprState *state, Node *node);
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
PlanState *parent);
-static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
+static void ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *aref,
PlanState *parent, ExprState *state,
Datum *resv, bool *resnull);
static bool isAssignmentIndirectionExpr(Expr *expr);
@@ -791,11 +791,11 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
break;
}
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *aref = (ArrayRef *) node;
+ SubscriptingRef *aref = (SubscriptingRef *) node;
- ExecInitArrayRef(&scratch, aref, parent, state, resv, resnull);
+ ExecInitSubscriptingRef(&scratch, aref, parent, state, resv, resnull);
break;
}
@@ -1109,7 +1109,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
/*
* Use the CaseTestExpr mechanism to pass down the old
* value of the field being replaced; this is needed in
- * case the newval is itself a FieldStore or ArrayRef that
+ * case the newval is itself a FieldStore or SubscriptingRef that
* has to obtain and modify the old value. It's safe to
* reuse the CASE mechanism because there cannot be a CASE
* between here and where the value would be needed, and a
@@ -2306,31 +2306,40 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent)
}
/*
- * Prepare evaluation of an ArrayRef expression.
+ * Prepare evaluation of an SubscriptingRef expression.
*/
static void
-ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
+ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *aref, PlanState *parent,
ExprState *state, Datum *resv, bool *resnull)
{
bool isAssignment = (aref->refassgnexpr != NULL);
- ArrayRefState *arefstate = palloc0(sizeof(ArrayRefState));
+ SubscriptingRefState *arefstate = palloc0(sizeof(SubscriptingRefState));
List *adjust_jumps = NIL;
ListCell *lc;
int i;
+ FmgrInfo *eval_finfo, *nested_finfo;
- /* Fill constant fields of ArrayRefState */
+ eval_finfo = palloc0(sizeof(FmgrInfo));
+ nested_finfo = palloc0(sizeof(FmgrInfo));
+
+ fmgr_info(aref->refevalfunc, eval_finfo);
+ if (OidIsValid(aref->refnestedfunc))
+ {
+ fmgr_info(aref->refnestedfunc, nested_finfo);
+ }
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
+
+ /* Fill constant fields of SubscriptingRefState */
arefstate->isassignment = isAssignment;
arefstate->refelemtype = aref->refelemtype;
- arefstate->refattrlength = get_typlen(aref->refarraytype);
- get_typlenbyvalalign(aref->refelemtype,
- &arefstate->refelemlength,
- &arefstate->refelembyval,
- &arefstate->refelemalign);
+ arefstate->refattrlength = get_typlen(aref->refcontainertype);
/*
* Evaluate array input. It's safe to do so into resv/resnull, because we
* won't use that as target for any of the other subexpressions, and it'll
- * be overwritten by the final EEOP_ARRAYREF_FETCH/ASSIGN step, which is
+ * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
* pushed last.
*/
ExecInitExprRec(aref->refexpr, parent, state, resv, resnull);
@@ -2345,22 +2354,26 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
scratch->opcode = EEOP_JUMP_IF_NULL;
scratch->d.jump.jumpdone = -1; /* adjust later */
ExprEvalPushStep(state, scratch);
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
+
adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1);
}
/* Verify subscript list lengths are within limit */
- if (list_length(aref->refupperindexpr) > MAXDIM)
+ if (list_length(aref->refupperindexpr) > MAX_SUBSCRIPT_DEPTH)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
- list_length(aref->refupperindexpr), MAXDIM)));
+ list_length(aref->refupperindexpr), MAX_SUBSCRIPT_DEPTH)));
- if (list_length(aref->reflowerindexpr) > MAXDIM)
+ if (list_length(aref->reflowerindexpr) > MAX_SUBSCRIPT_DEPTH)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
- list_length(aref->reflowerindexpr), MAXDIM)));
+ list_length(aref->reflowerindexpr), MAX_SUBSCRIPT_DEPTH)));
/* Evaluate upper subscripts */
i = 0;
@@ -2382,13 +2395,17 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
ExecInitExprRec(e, parent, state,
&arefstate->subscriptvalue, &arefstate->subscriptnull);
- /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
- scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT;
- scratch->d.arrayref_subscript.state = arefstate;
- scratch->d.arrayref_subscript.off = i;
- scratch->d.arrayref_subscript.isupper = true;
- scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */
+ /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
+ scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
+ scratch->d.sbsref_subscript.state = arefstate;
+ scratch->d.sbsref_subscript.off = i;
+ scratch->d.sbsref_subscript.isupper = true;
+ scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
ExprEvalPushStep(state, scratch);
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
+
adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1);
i++;
@@ -2415,13 +2432,17 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
ExecInitExprRec(e, parent, state,
&arefstate->subscriptvalue, &arefstate->subscriptnull);
- /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
- scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT;
- scratch->d.arrayref_subscript.state = arefstate;
- scratch->d.arrayref_subscript.off = i;
- scratch->d.arrayref_subscript.isupper = false;
- scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */
+ /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
+ scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
+ scratch->d.sbsref_subscript.state = arefstate;
+ scratch->d.sbsref_subscript.off = i;
+ scratch->d.sbsref_subscript.isupper = false;
+ scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
ExprEvalPushStep(state, scratch);
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
+
adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1);
i++;
@@ -2440,7 +2461,7 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
/*
* We might have a nested-assignment situation, in which the
- * refassgnexpr is itself a FieldStore or ArrayRef that needs to
+ * refassgnexpr is itself a FieldStore or SubscriptingRef that needs to
* obtain and modify the previous value of the array element or slice
* being replaced. If so, we have to extract that value from the
* array and pass it down via the CaseTextExpr mechanism. It's safe
@@ -2454,12 +2475,15 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
*/
if (isAssignmentIndirectionExpr(aref->refassgnexpr))
{
- scratch->opcode = EEOP_ARRAYREF_OLD;
- scratch->d.arrayref.state = arefstate;
+ scratch->opcode = EEOP_SBSREF_OLD;
+ scratch->d.sbsref.state = arefstate;
ExprEvalPushStep(state, scratch);
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
}
- /* ARRAYREF_OLD puts extracted value into prevvalue/prevnull */
+ /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
save_innermost_caseval = state->innermost_caseval;
save_innermost_casenull = state->innermost_casenull;
state->innermost_caseval = &arefstate->prevvalue;
@@ -2473,16 +2497,24 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
state->innermost_casenull = save_innermost_casenull;
/* and perform the assignment */
- scratch->opcode = EEOP_ARRAYREF_ASSIGN;
- scratch->d.arrayref.state = arefstate;
+ scratch->opcode = EEOP_SBSREF_ASSIGN;
+ scratch->d.sbsref.state = arefstate;
ExprEvalPushStep(state, scratch);
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
+
}
else
{
/* array fetch is much simpler */
- scratch->opcode = EEOP_ARRAYREF_FETCH;
- scratch->d.arrayref.state = arefstate;
+ scratch->opcode = EEOP_SBSREF_FETCH;
+ scratch->d.sbsref.state = arefstate;
ExprEvalPushStep(state, scratch);
+
+ scratch->d.sbsref.eval_finfo = eval_finfo;
+ scratch->d.sbsref.nested_finfo = nested_finfo;
+
}
/* adjust jump targets */
@@ -2490,10 +2522,10 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
{
ExprEvalStep *as = &state->steps[lfirst_int(lc)];
- if (as->opcode == EEOP_ARRAYREF_SUBSCRIPT)
+ if (as->opcode == EEOP_SBSREF_SUBSCRIPT)
{
- Assert(as->d.arrayref_subscript.jumpdone == -1);
- as->d.arrayref_subscript.jumpdone = state->steps_len;
+ Assert(as->d.sbsref_subscript.jumpdone == -1);
+ as->d.sbsref_subscript.jumpdone = state->steps_len;
}
else
{
@@ -2505,8 +2537,8 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
}
/*
- * Helper for preparing ArrayRef expressions for evaluation: is expr a nested
- * FieldStore or ArrayRef that might need the old element value passed down?
+ * Helper for preparing SubscriptingRef expressions for evaluation: is expr a nested
+ * FieldStore or SubscriptingRef that might need the old element value passed down?
*
* (We could use this in FieldStore too, but in that case passing the old
* value is so cheap there's no need.)
@@ -2523,11 +2555,11 @@ isAssignmentIndirectionExpr(Expr *expr)
if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
return true;
}
- else if (IsA(expr, ArrayRef))
+ else if (IsA(expr, SubscriptingRef))
{
- ArrayRef *arrayRef = (ArrayRef *) expr;
+ SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
- if (arrayRef->refexpr && IsA(arrayRef->refexpr, CaseTestExpr))
+ if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
return true;
}
return false;
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index fed0052..b8fe052 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -348,10 +348,10 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_FIELDSELECT,
&&CASE_EEOP_FIELDSTORE_DEFORM,
&&CASE_EEOP_FIELDSTORE_FORM,
- &&CASE_EEOP_ARRAYREF_SUBSCRIPT,
- &&CASE_EEOP_ARRAYREF_OLD,
- &&CASE_EEOP_ARRAYREF_ASSIGN,
- &&CASE_EEOP_ARRAYREF_FETCH,
+ &&CASE_EEOP_SBSREF_SUBSCRIPT,
+ &&CASE_EEOP_SBSREF_OLD,
+ &&CASE_EEOP_SBSREF_ASSIGN,
+ &&CASE_EEOP_SBSREF_FETCH,
&&CASE_EEOP_DOMAIN_TESTVAL,
&&CASE_EEOP_DOMAIN_NOTNULL,
&&CASE_EEOP_DOMAIN_CHECK,
@@ -1369,43 +1369,43 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT)
+ EEO_CASE(EEOP_SBSREF_SUBSCRIPT)
{
/* Process an array subscript */
/* too complex for an inline implementation */
- if (ExecEvalArrayRefSubscript(state, op))
+ if (ExecEvalSubscriptingRef(state, op))
{
EEO_NEXT();
}
else
{
- /* Subscript is null, short-circuit ArrayRef to NULL */
- EEO_JUMP(op->d.arrayref_subscript.jumpdone);
+ /* Subscript is null, short-circuit SubscriptingRef to NULL */
+ EEO_JUMP(op->d.sbsref_subscript.jumpdone);
}
}
- EEO_CASE(EEOP_ARRAYREF_OLD)
+ EEO_CASE(EEOP_SBSREF_OLD)
{
/*
- * Fetch the old value in an arrayref assignment, in case it's
+ * Fetch the old value in an sbsref assignment, in case it's
* referenced (via a CaseTestExpr) inside the assignment
* expression.
*/
/* too complex for an inline implementation */
- ExecEvalArrayRefOld(state, op);
+ ExecEvalSubscriptingRefOld(state, op);
EEO_NEXT();
}
/*
- * Perform ArrayRef assignment
+ * Perform SubscriptingRef assignment
*/
- EEO_CASE(EEOP_ARRAYREF_ASSIGN)
+ EEO_CASE(EEOP_SBSREF_ASSIGN)
{
/* too complex for an inline implementation */
- ExecEvalArrayRefAssign(state, op);
+ ExecEvalSubscriptingRefAssign(state, op);
EEO_NEXT();
}
@@ -1413,10 +1413,10 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
/*
* Fetch subset of an array.
*/
- EEO_CASE(EEOP_ARRAYREF_FETCH)
+ EEO_CASE(EEOP_SBSREF_FETCH)
{
/* too complex for an inline implementation */
- ExecEvalArrayRefFetch(state, op);
+ ExecEvalSubscriptingRefFetch(state, op);
EEO_NEXT();
}
@@ -2578,21 +2578,21 @@ ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext
}
/*
- * Process a subscript in an ArrayRef expression.
+ * Process a subscript in an SubscriptingRef expression.
*
* If subscript is NULL, throw error in assignment case, or in fetch case
* set result to NULL and return false (instructing caller to skip the rest
- * of the ArrayRef sequence).
+ * of the SubscriptingRef sequence).
*
* Subscript expression result is in subscriptvalue/subscriptnull.
* On success, integer subscript value has been saved in upperindex[] or
* lowerindex[] for use later.
*/
bool
-ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op)
+ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref_subscript.state;
- int *indexes;
+ SubscriptingRefState *arefstate = op->d.sbsref_subscript.state;
+ Datum *indexes;
int off;
/* If any index expr yields NULL, result is NULL or error */
@@ -2607,68 +2607,43 @@ ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op)
}
/* Convert datum to int, save in appropriate place */
- if (op->d.arrayref_subscript.isupper)
- indexes = arefstate->upperindex;
+ if (op->d.sbsref_subscript.isupper)
+ indexes = arefstate->upper;
else
- indexes = arefstate->lowerindex;
- off = op->d.arrayref_subscript.off;
+ indexes = arefstate->lower;
+ off = op->d.sbsref_subscript.off;
- indexes[off] = DatumGetInt32(arefstate->subscriptvalue);
+ indexes[off] = arefstate->subscriptvalue;
return true;
}
/*
- * Evaluate ArrayRef fetch.
+ * Evaluate SubscriptingRef fetch.
*
* Source array is in step's result variable.
*/
void
-ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op)
+ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref.state;
-
/* Should not get here if source array (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 = FunctionCall2(op->d.sbsref.eval_finfo,
+ PointerGetDatum(*op->resvalue),
+ PointerGetDatum(op));
}
/*
- * Compute old array element/slice value for an ArrayRef assignment
+ * Compute old array element/slice value for an SubscriptingRef assignment
* expression. Will only be generated if the new-value subexpression
- * contains ArrayRef or FieldStore. The value is stored into the
- * ArrayRefState's prevvalue/prevnull fields.
+ * contains SubscriptingRef or FieldStore. The value is stored into the
+ * SubscriptingRefState's prevvalue/prevnull fields.
*/
void
-ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op)
+ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref.state;
+ SubscriptingRefState *arefstate = op->d.sbsref.state;
if (*op->resnull)
{
@@ -2676,99 +2651,42 @@ ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op)
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);
- }
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;
+ arefstate->prevvalue = FunctionCall2(op->d.sbsref.nested_finfo,
+ PointerGetDatum(*op->resvalue),
+ PointerGetDatum(op));
+
+ if (arefstate->numlower != 0)
+ arefstate->prevnull = false;
+
}
}
/*
- * Evaluate ArrayRef assignment.
+ * Evaluate SubscriptingRef assignment.
*
* Input array (possibly null) is in result area, replacement value is in
- * ArrayRefState's replacevalue/replacenull.
+ * SubscriptingRefState's replacevalue/replacenull.
*/
void
-ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op)
+ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op)
{
- ArrayRefState *arefstate = op->d.arrayref.state;
-
+ SubscriptingRefState *arefstate = op->d.sbsref.state;
/*
* For an assignment to a fixed-length array type, both the original array
* and the value to be assigned into it must be non-NULL, else we punt and
* return the original array.
*/
- if (arefstate->refattrlength > 0) /* fixed-length array? */
+ if (arefstate->refattrlength > 0)
{
if (*op->resnull || arefstate->replacenull)
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);
- }
+ *op->resvalue = FunctionCall2(op->d.sbsref.eval_finfo,
+ PointerGetDatum(*op->resvalue),
+ PointerGetDatum(op));
}
/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2d2a9d0..20247c7 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1413,17 +1413,19 @@ _copyWindowFunc(const WindowFunc *from)
}
/*
- * _copyArrayRef
+ * _copySubscriptingRef
*/
-static ArrayRef *
-_copyArrayRef(const ArrayRef *from)
+static SubscriptingRef *
+_copySubscriptingRef(const SubscriptingRef *from)
{
- ArrayRef *newnode = makeNode(ArrayRef);
+ SubscriptingRef *newnode = makeNode(SubscriptingRef);
- COPY_SCALAR_FIELD(refarraytype);
+ COPY_SCALAR_FIELD(refcontainertype);
COPY_SCALAR_FIELD(refelemtype);
COPY_SCALAR_FIELD(reftypmod);
COPY_SCALAR_FIELD(refcollid);
+ COPY_SCALAR_FIELD(refevalfunc);
+ COPY_SCALAR_FIELD(refnestedfunc);
COPY_NODE_FIELD(refupperindexpr);
COPY_NODE_FIELD(reflowerindexpr);
COPY_NODE_FIELD(refexpr);
@@ -4851,8 +4853,8 @@ copyObjectImpl(const void *from)
case T_WindowFunc:
retval = _copyWindowFunc(from);
break;
- case T_ArrayRef:
- retval = _copyArrayRef(from);
+ case T_SubscriptingRef:
+ retval = _copySubscriptingRef(from);
break;
case T_FuncExpr:
retval = _copyFuncExpr(from);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index b5459cd..f097c92 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -264,12 +264,14 @@ _equalWindowFunc(const WindowFunc *a, const WindowFunc *b)
}
static bool
-_equalArrayRef(const ArrayRef *a, const ArrayRef *b)
+_equalSubscriptingRef(const SubscriptingRef *a, const SubscriptingRef *b)
{
- COMPARE_SCALAR_FIELD(refarraytype);
+ COMPARE_SCALAR_FIELD(refcontainertype);
COMPARE_SCALAR_FIELD(refelemtype);
COMPARE_SCALAR_FIELD(reftypmod);
COMPARE_SCALAR_FIELD(refcollid);
+ COMPARE_SCALAR_FIELD(refevalfunc);
+ COMPARE_SCALAR_FIELD(refnestedfunc);
COMPARE_NODE_FIELD(refupperindexpr);
COMPARE_NODE_FIELD(reflowerindexpr);
COMPARE_NODE_FIELD(refexpr);
@@ -3013,8 +3015,8 @@ equal(const void *a, const void *b)
case T_WindowFunc:
retval = _equalWindowFunc(a, b);
break;
- case T_ArrayRef:
- retval = _equalArrayRef(a, b);
+ case T_SubscriptingRef:
+ retval = _equalSubscriptingRef(a, b);
break;
case T_FuncExpr:
retval = _equalFuncExpr(a, b);
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 3e8189c..985c282 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -66,15 +66,15 @@ exprType(const Node *expr)
case T_WindowFunc:
type = ((const WindowFunc *) expr)->wintype;
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- const ArrayRef *arrayref = (const ArrayRef *) expr;
+ const SubscriptingRef *sbsref = (const SubscriptingRef *) expr;
/* slice and/or store operations yield the array type */
- if (arrayref->reflowerindexpr || arrayref->refassgnexpr)
- type = arrayref->refarraytype;
+ if (IsAssignment(sbsref) || sbsref->reflowerindexpr)
+ type = sbsref->refcontainertype;
else
- type = arrayref->refelemtype;
+ type = sbsref->refelemtype;
}
break;
case T_FuncExpr:
@@ -286,9 +286,9 @@ exprTypmod(const Node *expr)
return ((const Const *) expr)->consttypmod;
case T_Param:
return ((const Param *) expr)->paramtypmod;
- case T_ArrayRef:
+ case T_SubscriptingRef:
/* typmod is the same for array or element */
- return ((const ArrayRef *) expr)->reftypmod;
+ return ((const SubscriptingRef *) expr)->reftypmod;
case T_FuncExpr:
{
int32 coercedTypmod;
@@ -772,8 +772,8 @@ exprCollation(const Node *expr)
case T_WindowFunc:
coll = ((const WindowFunc *) expr)->wincollid;
break;
- case T_ArrayRef:
- coll = ((const ArrayRef *) expr)->refcollid;
+ case T_SubscriptingRef:
+ coll = ((const SubscriptingRef *) expr)->refcollid;
break;
case T_FuncExpr:
coll = ((const FuncExpr *) expr)->funccollid;
@@ -1016,8 +1016,8 @@ exprSetCollation(Node *expr, Oid collation)
case T_WindowFunc:
((WindowFunc *) expr)->wincollid = collation;
break;
- case T_ArrayRef:
- ((ArrayRef *) expr)->refcollid = collation;
+ case T_SubscriptingRef:
+ ((SubscriptingRef *) expr)->refcollid = collation;
break;
case T_FuncExpr:
((FuncExpr *) expr)->funccollid = collation;
@@ -1244,9 +1244,9 @@ exprLocation(const Node *expr)
/* function name should always be the first thing */
loc = ((const WindowFunc *) expr)->location;
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
/* just use array argument's location */
- loc = exprLocation((Node *) ((const ArrayRef *) expr)->refexpr);
+ loc = exprLocation((Node *) ((const SubscriptingRef *) expr)->refexpr);
break;
case T_FuncExpr:
{
@@ -1690,6 +1690,14 @@ check_functions_in_node(Node *node, check_function_callback checker,
return true;
}
break;
+ case T_SubscriptingRef:
+ {
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
+
+ if (checker(sbsref->refevalfunc, context))
+ return true;
+ }
+ break;
case T_FuncExpr:
{
FuncExpr *expr = (FuncExpr *) node;
@@ -1940,21 +1948,25 @@ expression_tree_walker(Node *node,
return true;
}
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *aref = (ArrayRef *) node;
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
/* recurse directly for upper/lower array index lists */
- if (expression_tree_walker((Node *) aref->refupperindexpr,
+ if (expression_tree_walker((Node *) sbsref->refupperindexpr,
walker, context))
return true;
- if (expression_tree_walker((Node *) aref->reflowerindexpr,
+ if (expression_tree_walker((Node *) sbsref->reflowerindexpr,
walker, context))
return true;
/* walker must see the refexpr and refassgnexpr, however */
- if (walker(aref->refexpr, context))
+ if (walker(sbsref->refexpr, context))
return true;
- if (walker(aref->refassgnexpr, context))
+
+ if (!IsAssignment(node))
+ break;
+
+ if (walker(sbsref->refassgnexpr, context))
return true;
}
break;
@@ -2550,20 +2562,21 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *arrayref = (ArrayRef *) node;
- ArrayRef *newnode;
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
+ SubscriptingRef *newnode;
- FLATCOPY(newnode, arrayref, ArrayRef);
- MUTATE(newnode->refupperindexpr, arrayref->refupperindexpr,
+ FLATCOPY(newnode, sbsref, SubscriptingRef);
+ MUTATE(newnode->refupperindexpr, sbsref->refupperindexpr,
List *);
- MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr,
+ MUTATE(newnode->reflowerindexpr, sbsref->reflowerindexpr,
List *);
- MUTATE(newnode->refexpr, arrayref->refexpr,
+ MUTATE(newnode->refexpr, sbsref->refexpr,
Expr *);
- MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr,
+ MUTATE(newnode->refassgnexpr, sbsref->refassgnexpr,
Expr *);
+
return (Node *) newnode;
}
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 98f6768..1c21be3 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1152,14 +1152,16 @@ _outWindowFunc(StringInfo str, const WindowFunc *node)
}
static void
-_outArrayRef(StringInfo str, const ArrayRef *node)
+_outSubscriptingRef(StringInfo str, const SubscriptingRef *node)
{
- WRITE_NODE_TYPE("ARRAYREF");
+ WRITE_NODE_TYPE("SUBSCRIPTINGREF");
- WRITE_OID_FIELD(refarraytype);
+ WRITE_OID_FIELD(refcontainertype);
WRITE_OID_FIELD(refelemtype);
WRITE_INT_FIELD(reftypmod);
WRITE_OID_FIELD(refcollid);
+ WRITE_OID_FIELD(refevalfunc);
+ WRITE_OID_FIELD(refnestedfunc);
WRITE_NODE_FIELD(refupperindexpr);
WRITE_NODE_FIELD(reflowerindexpr);
WRITE_NODE_FIELD(refexpr);
@@ -3751,8 +3753,8 @@ outNode(StringInfo str, const void *obj)
case T_WindowFunc:
_outWindowFunc(str, obj);
break;
- case T_ArrayRef:
- _outArrayRef(str, obj);
+ case T_SubscriptingRef:
+ _outSubscriptingRef(str, obj);
break;
case T_FuncExpr:
_outFuncExpr(str, obj);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index f9a227e..aa6a5e8 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -633,17 +633,19 @@ _readWindowFunc(void)
}
/*
- * _readArrayRef
+ * _readSubscriptingRef
*/
-static ArrayRef *
-_readArrayRef(void)
+static SubscriptingRef *
+_readSubscriptingRef(void)
{
- READ_LOCALS(ArrayRef);
+ READ_LOCALS(SubscriptingRef);
- READ_OID_FIELD(refarraytype);
+ READ_OID_FIELD(refcontainertype);
READ_OID_FIELD(refelemtype);
READ_INT_FIELD(reftypmod);
READ_OID_FIELD(refcollid);
+ READ_OID_FIELD(refevalfunc);
+ READ_OID_FIELD(refnestedfunc);
READ_NODE_FIELD(refupperindexpr);
READ_NODE_FIELD(reflowerindexpr);
READ_NODE_FIELD(refexpr);
@@ -2452,8 +2454,8 @@ parseNodeString(void)
return_value = _readGroupingFunc();
else if (MATCH("WINDOWFUNC", 10))
return_value = _readWindowFunc();
- else if (MATCH("ARRAYREF", 8))
- return_value = _readArrayRef();
+ else if (MATCH("SUBSCRIPTINGREF", 15))
+ return_value = _readSubscriptingRef();
else if (MATCH("FUNCEXPR", 8))
return_value = _readFuncExpr();
else if (MATCH("NAMEDARGEXPR", 12))
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 52643d0..3165fc7 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3542,6 +3542,11 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
context->total.per_tuple +=
get_func_cost(((FuncExpr *) node)->funcid) * cpu_operator_cost;
}
+ else if (IsA(node, SubscriptingRef))
+ {
+ context->total.per_tuple +=
+ get_func_cost(((SubscriptingRef *) node)->refevalfunc) * cpu_operator_cost;
+ }
else if (IsA(node, OpExpr) ||
IsA(node, DistinctExpr) ||
IsA(node, NullIfExpr))
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index c192dc4..953d601 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1370,6 +1370,11 @@ fix_expr_common(PlannerInfo *root, Node *node)
record_plan_function_dependency(root,
((FuncExpr *) node)->funcid);
}
+ else if (IsA(node, SubscriptingRef))
+ {
+ record_plan_function_dependency(root,
+ ((SubscriptingRef *) node)->refevalfunc);
+ }
else if (IsA(node, OpExpr))
{
set_opfuncid((OpExpr *) node);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a1dafc8..16d1535 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1299,12 +1299,10 @@ contain_nonstrict_functions_walker(Node *node, void *context)
/* a window function could return non-null with null input */
return true;
}
- if (IsA(node, ArrayRef))
+ if (IsA(node, SubscriptingRef))
{
/* array assignment is nonstrict, but subscripting is strict */
- if (((ArrayRef *) node)->refassgnexpr != NULL)
- return true;
- /* else fall through to check args */
+ return true;
}
if (IsA(node, DistinctExpr))
{
@@ -1480,7 +1478,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_Var:
case T_Const:
case T_Param:
- case T_ArrayRef:
case T_ArrayExpr:
case T_FieldSelect:
case T_FieldStore:
@@ -1510,6 +1507,7 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_ScalarArrayOpExpr:
case T_CoerceViaIO:
case T_ArrayCoerceExpr:
+ case T_SubscriptingRef:
/*
* If node contains a leaky function call, and there's any Var
@@ -3555,7 +3553,7 @@ eval_const_expressions_mutator(Node *node,
* For any node type not handled above, we recurse using
* expression_tree_mutator, which will copy the node unchanged but try to
* simplify its arguments (if any) using this routine. For example: we
- * cannot eliminate an ArrayRef node, but we might be able to simplify
+ * cannot eliminate an SubscriptingRef node, but we might be able to simplify
* constant expressions in its subscripts.
*/
return expression_tree_mutator(node, eval_const_expressions_mutator,
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 567dd54..9c78576 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -973,13 +973,10 @@ transformInsertRow(ParseState *pstate, List *exprlist,
expr = (Expr *) linitial(fstore->newvals);
}
- else if (IsA(expr, ArrayRef))
+ else if (IsA(expr, SubscriptingRef) && IsAssignment(expr))
{
- ArrayRef *aref = (ArrayRef *) expr;
-
- if (aref->refassgnexpr == NULL)
- break;
- expr = aref->refassgnexpr;
+ SubscriptingRef *sbsref = (SubscriptingRef *) expr;
+ expr = sbsref->refassgnexpr;
}
else
break;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 4f9b1a7..3126f10 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -472,13 +472,13 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
/* process subscripts before this field selection */
if (subscripts)
- result = (Node *) transformArraySubscripts(pstate,
- result,
- exprType(result),
- InvalidOid,
- exprTypmod(result),
- subscripts,
- NULL);
+ result = (Node *) transformContainerSubscripts(pstate,
+ result,
+ exprType(result),
+ InvalidOid,
+ exprTypmod(result),
+ subscripts,
+ NULL);
subscripts = NIL;
newresult = ParseFuncOrColumn(pstate,
@@ -493,13 +493,13 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
}
/* process trailing subscripts, if any */
if (subscripts)
- result = (Node *) transformArraySubscripts(pstate,
- result,
- exprType(result),
- InvalidOid,
- exprTypmod(result),
- subscripts,
- NULL);
+ result = (Node *) transformContainerSubscripts(pstate,
+ result,
+ exprType(result),
+ InvalidOid,
+ exprTypmod(result),
+ subscripts,
+ NULL);
return result;
}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index fb3d117..388b184 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -204,18 +204,22 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
/*
* transformArrayType()
- * Identify the types involved in a subscripting operation
+ * Identify the types involved in a subscripting operation for array
*
* 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.
+ *
+ * NOTE: This part of type-specific code is not separated into type-specific
+ * subscripting procedure for now, but it does not affect on the whole logic,
+ * since InvalidOid will be return in case of other types not an error.
+ * An error will appears only if a subscripting procedure is not defined.
*/
Oid
-transformArrayType(Oid *arrayType, int32 *arrayTypmod)
+transformArrayType(Oid *containerType, int32 *containerTypmod)
{
- Oid origArrayType = *arrayType;
Oid elementType;
HeapTuple type_tuple_array;
Form_pg_type type_struct_array;
@@ -227,7 +231,7 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod)
* itself. (Note that we provide no method whereby the creator of a
* domain over an array 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,25 +240,20 @@ 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;
+ if (*containerType == INT2VECTOROID)
+ *containerType = INT2ARRAYOID;
+ else if (*containerType == OIDVECTOROID)
+ *containerType = OIDARRAYOID;
/* Get the type tuple for the array */
- type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType));
+ type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*containerType));
if (!HeapTupleIsValid(type_tuple_array))
- elog(ERROR, "cache lookup failed for type %u", *arrayType);
+ elog(ERROR, "cache lookup failed for type %u", *containerType);
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);
@@ -262,61 +261,73 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod)
}
/*
- * 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 placend in
+ * separate procedure indicated by typsubsparse. 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.) If domain verification failed we assume, that element type
+ * must be the same as container type (e.g. in case of jsonb).
+ * 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 transformArrayType,
+ * 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)
+
+Node *
+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;
+ RegProcedure typsubsparse = get_typsubsparse(containerType);
+
+ if (!OidIsValid(typsubsparse))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("cannot subscript type %s because it does not support subscripting",
+ format_type_be(containerType))));
- /*
- * 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.
- */
+ /* Caller may or may not have bothered to determine elementType. */
if (!OidIsValid(elementType))
- elementType = transformArrayType(&arrayType, &arrayTypMod);
+ elementType = containerType;
/*
- * 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 +356,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 +363,32 @@ 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->refelemtype = elementType;
+ 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;
-
- return aref;
+ sbsref->refupperindexpr = upperIndexpr;
+ sbsref->reflowerindexpr = lowerIndexpr;
+ sbsref->refindexprslice = indexprSlice;
+ sbsref->refexpr = (Expr *) containerBase;
+
+ return (Node *) OidFunctionCall3(typsubsparse,
+ BoolGetDatum(assignFrom != NULL),
+ PointerGetDatum(sbsref),
+ PointerGetDatum(pstate));
}
/*
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index c46c3b3..4aee4cd 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -821,41 +821,24 @@ transformAssignmentIndirection(ParseState *pstate,
/* 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 (targetTypeId != InvalidOid)
+ result = coerce_to_target_type(pstate,
+ rhs, exprType(rhs),
+ targetTypeId, targetTypMod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ else
+ result = rhs;
+
if (result == NULL)
- {
- 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
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("subfield \"%s\" is of 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)));
- }
+ result = rhs;
return result;
}
/*
- * helper for transformAssignmentIndirection: process array assignment
+ * helper for transformAssignmentIndirection: process container assignment
*/
static Node *
transformAssignmentSubscripts(ParseState *pstate,
@@ -871,55 +854,55 @@ transformAssignmentSubscripts(ParseState *pstate,
int location)
{
Node *result;
- Oid arrayType;
- int32 arrayTypMod;
+ Oid containerType;
+ int32 containerTypMod;
Oid elementTypeId;
Oid typeNeeded;
Oid collationNeeded;
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;
+ elementTypeId = transformArrayType(&containerType, &containerTypMod);
/* Identify type that RHS must provide */
- typeNeeded = isSlice ? arrayType : elementTypeId;
+ typeNeeded = isSlice ? containerType : elementTypeId;
/*
- * Array normally has same collation as elements, but there's an
- * exception: we might be subscripting a domain over an array type. In
+ * 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 (containerType == targetTypeId)
collationNeeded = targetCollation;
else
- collationNeeded = get_typcollation(arrayType);
+ collationNeeded = get_typcollation(containerType);
- /* recurse to create appropriate RHS for array assign */
+ /* recurse to create appropriate RHS for container assign */
rhs = transformAssignmentIndirection(pstate,
NULL,
targetName,
true,
typeNeeded,
- arrayTypMod,
+ containerTypMod,
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)
+ result = (Node *) transformContainerSubscripts(pstate,
+ basenode,
+ containerType,
+ exprType(rhs),
+ containerTypMod,
+ subscripts,
+ rhs);
+
+ /* If target was a domain over container, need to coerce up to the domain */
+ if (containerType != targetTypeId)
{
Oid resulttype = exprType(result);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 4dcb713..56be6a9 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -951,7 +951,7 @@ process_matched_tle(TargetEntry *src_tle,
/*----------
* Multiple assignments to same attribute. Allow only if all are
- * FieldStore or ArrayRef assignment operations. This is a bit
+ * FieldStore or SubscriptingRef assignment operations. This is a bit
* tricky because what we may actually be looking at is a nest of
* such nodes; consider
* UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
@@ -959,7 +959,7 @@ process_matched_tle(TargetEntry *src_tle,
* FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
* FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
* However, we can ignore the substructure and just consider the top
- * FieldStore or ArrayRef from each assignment, because it works to
+ * FieldStore or SubscriptingRef from each assignment, because it works to
* combine these as
* FieldStore(FieldStore(col, fld1,
* FieldStore(placeholder, subfld1, x)),
@@ -969,7 +969,7 @@ process_matched_tle(TargetEntry *src_tle,
*
* For FieldStore, instead of nesting we can generate a single
* FieldStore with multiple target fields. We must nest when
- * ArrayRefs are involved though.
+ * SubscriptingRefs are involved though.
*----------
*/
src_expr = (Node *) src_tle->expr;
@@ -1028,13 +1028,15 @@ process_matched_tle(TargetEntry *src_tle,
}
newexpr = (Node *) fstore;
}
- else if (IsA(src_expr, ArrayRef))
+ else if (IsA(src_expr, SubscriptingRef))
{
- ArrayRef *aref = makeNode(ArrayRef);
+ NodeTag sbstag = nodeTag(src_expr);
+ Size nodeSize = sizeof(SubscriptingRef);
+ SubscriptingRef *sbsref = (SubscriptingRef *) newNode(nodeSize, sbstag);
- memcpy(aref, src_expr, sizeof(ArrayRef));
- aref->refexpr = (Expr *) prior_expr;
- newexpr = (Node *) aref;
+ memcpy(sbsref, src_expr, nodeSize);
+ sbsref->refexpr = (Expr *) prior_expr;
+ newexpr = (Node *) sbsref;
}
else
{
@@ -1061,14 +1063,12 @@ get_assignment_input(Node *node)
return (Node *) fstore->arg;
}
- else if (IsA(node, ArrayRef))
+ else if (IsA(node, SubscriptingRef) && IsAssignment(node))
{
- ArrayRef *aref = (ArrayRef *) node;
-
- if (aref->refassgnexpr == NULL)
- return NULL;
- return (Node *) aref->refexpr;
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
+ return (Node *) sbsref->refexpr;
}
+
return NULL;
}
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index d9c8aa5..ef0dcf3 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -24,13 +24,19 @@
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
+#include "executor/execExpr.h"
#include "utils/array.h"
#include "utils/arrayaccess.h"
#include "utils/builtins.h"
#include "utils/datum.h"
+#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/typcache.h"
+#include "parser/parse_node.h"
+#include "parser/parse_coerce.h"
/*
@@ -158,7 +164,6 @@ static int width_bucket_array_variable(Datum operand,
Oid collation,
TypeCacheEntry *typentry);
-
/*
* array_in :
* converts an array from the external format in "string" to
@@ -6508,3 +6513,275 @@ width_bucket_array_variable(Datum operand,
return left;
}
+
+/*
+ * Perform an actual data extraction or modification for the array
+ * subscripting. As a result the extracted Datum or the modified containers
+ * value will be returned.
+ */
+Datum
+array_subscripting_assign(PG_FUNCTION_ARGS)
+{
+ Datum containerSource = PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+ SubscriptingRefState *sbstate = step->d.sbsref.state;
+
+ bool is_slice = (sbstate->numlower != 0);
+ IntArray u_index, l_index;
+ bool eisnull = *(step->resnull);
+ int i = 0;
+
+ if (sbstate->refelemlength == 0)
+ {
+ /* do one-time catalog lookups for type info */
+ get_typlenbyvalalign(sbstate->refelemtype,
+ &sbstate->refelemlength,
+ &sbstate->refelembyval,
+ &sbstate->refelemalign);
+ }
+
+ for(i = 0; i < sbstate->numupper; i++)
+ u_index.indx[i] = DatumGetInt32(sbstate->upper[i]);
+
+ if (is_slice)
+ {
+ for(i = 0; i < sbstate->numlower; i++)
+ l_index.indx[i] = DatumGetInt32(sbstate->lower[i]);
+ }
+
+ /*
+ * 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 (eisnull)
+ {
+ containerSource = PointerGetDatum(construct_empty_array(sbstate->refelemtype));
+ *step->resnull = false;
+ eisnull = false;
+ }
+
+ if (!is_slice)
+ return array_set_element(containerSource, sbstate->numupper,
+ u_index.indx,
+ sbstate->replacevalue,
+ sbstate->replacenull,
+ sbstate->refattrlength,
+ sbstate->refelemlength,
+ sbstate->refelembyval,
+ sbstate->refelemalign);
+ else
+ return array_set_slice(containerSource, sbstate->numupper,
+ u_index.indx, l_index.indx,
+ sbstate->upperprovided,
+ sbstate->lowerprovided,
+ sbstate->replacevalue,
+ sbstate->replacenull,
+ sbstate->refattrlength,
+ sbstate->refelemlength,
+ sbstate->refelembyval,
+ sbstate->refelemalign);
+}
+
+Datum
+array_subscripting_fetch(PG_FUNCTION_ARGS)
+{
+ Datum containerSource = PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+ SubscriptingRefState *sbstate = step->d.sbsref.state;
+ bool is_slice = (sbstate->numlower != 0);
+ IntArray u_index, l_index;
+ int i = 0;
+
+ if (sbstate->refelemlength == 0)
+ {
+ /* do one-time catalog lookups for type info */
+ get_typlenbyvalalign(sbstate->refelemtype,
+ &sbstate->refelemlength,
+ &sbstate->refelembyval,
+ &sbstate->refelemalign);
+ }
+
+ for(i = 0; i < sbstate->numupper; i++)
+ u_index.indx[i] = DatumGetInt32(sbstate->upper[i]);
+
+ if (is_slice)
+ {
+ for(i = 0; i < sbstate->numlower; i++)
+ l_index.indx[i] = DatumGetInt32(sbstate->lower[i]);
+ }
+
+ if (!is_slice)
+ return array_get_element(containerSource, sbstate->numupper,
+ u_index.indx,
+ sbstate->refattrlength,
+ sbstate->refelemlength,
+ sbstate->refelembyval,
+ sbstate->refelemalign,
+ step->resnull);
+ else
+ return array_get_slice(containerSource, sbstate->numupper,
+ u_index.indx, l_index.indx,
+ sbstate->upperprovided,
+ sbstate->lowerprovided,
+ sbstate->refattrlength,
+ sbstate->refelemlength,
+ sbstate->refelembyval,
+ sbstate->refelemalign);
+}
+
+/*
+ * Handle array-type subscripting logic.
+ */
+Datum
+array_subscript_parse(PG_FUNCTION_ARGS)
+{
+ bool isAssignment = PG_GETARG_BOOL(0);
+ SubscriptingRef *sbsref = (SubscriptingRef *) PG_GETARG_POINTER(1);
+ ParseState *pstate = (ParseState *) PG_GETARG_POINTER(2);
+ Node *node = (Node *) sbsref;
+ Oid array_type = sbsref->refcontainertype;
+ int32 array_typ_mode = (int32) sbsref->reftypmod;
+ bool is_slice = sbsref->reflowerindexpr != NIL;
+ Oid typeneeded = InvalidOid,
+ typesource = InvalidOid;
+ Node *new_from;
+ Oid element_type_id;
+ Node *subexpr;
+ List *upperIndexpr = NIL;
+ List *lowerIndexpr = NIL;
+ ListCell *u, *l, *s;
+
+ /*
+ * Caller may or may not have bothered to determine elementType. Note
+ * that if the caller did do so, containerType/containerTypMod must be as modified
+ * by transformArrayType, ie, smash domain to base type.
+ */
+ element_type_id = transformArrayType(&array_type, &array_typ_mode);
+ sbsref->refelemtype = element_type_id;
+
+ foreach(u, sbsref->refupperindexpr)
+ {
+ subexpr = (Node *) lfirst(u);
+
+ if (subexpr == NULL)
+ {
+ upperIndexpr = lappend(upperIndexpr, subexpr);
+ continue;
+ }
+
+ 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(subexpr))));
+
+ upperIndexpr = lappend(upperIndexpr, subexpr);
+ }
+
+ sbsref->refupperindexpr = upperIndexpr;
+
+ forboth(l, sbsref->reflowerindexpr, s, sbsref->refindexprslice)
+ {
+ A_Indices *ai = (A_Indices *) lfirst(s);
+ subexpr = (Node *) lfirst(l);
+
+ if (subexpr == NULL && !ai->is_slice)
+ {
+ /* Make a constant 1 */
+ subexpr = (Node *) makeConst(INT4OID,
+ -1,
+ InvalidOid,
+ sizeof(int32),
+ Int32GetDatum(1),
+ false,
+ true); /* pass by value */
+ }
+
+ if (subexpr == NULL)
+ {
+ lowerIndexpr = lappend(lowerIndexpr, subexpr);
+ continue;
+ }
+
+ 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(subexpr))));
+
+ lowerIndexpr = lappend(lowerIndexpr, subexpr);
+ }
+
+ sbsref->reflowerindexpr = lowerIndexpr;
+
+ if (isAssignment)
+ {
+ SubscriptingRef *assignRef = (SubscriptingRef *) sbsref;
+ Node *assignExpr = (Node *) assignRef->refassgnexpr;
+
+ typesource = exprType(assignExpr);
+ typeneeded = is_slice ? sbsref->refcontainertype : sbsref->refelemtype;
+ new_from = coerce_to_target_type(pstate,
+ assignExpr, typesource,
+ typeneeded, sbsref->reftypmod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (new_from == 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(assignExpr))));
+ assignRef->refassgnexpr = (Expr *)new_from;
+
+ if (array_type != sbsref->refcontainertype)
+ {
+
+ node = coerce_to_target_type(pstate,
+ node, array_type,
+ sbsref->refcontainertype, sbsref->reftypmod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+
+ /* can fail if we had int2vector/oidvector, but not for true domains */
+ if (node == NULL && node->type != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_CANNOT_COERCE),
+ errmsg("cannot cast type %s to %s",
+ format_type_be(array_type),
+ format_type_be(sbsref->refcontainertype)),
+ parser_errposition(pstate, 0)));
+
+ PG_RETURN_POINTER(node);
+ }
+
+ }
+
+ sbsref->refnestedfunc = F_ARRAY_SUBSCRIPTING_FETCH;
+
+ if (isAssignment)
+ sbsref->refevalfunc = F_ARRAY_SUBSCRIPTING_ASSIGN;
+ else
+ sbsref->refevalfunc = F_ARRAY_SUBSCRIPTING_FETCH;
+
+ PG_RETURN_POINTER(sbsref);
+}
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 164f57e..1dc44d0 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -1146,23 +1146,34 @@ to_jsonb(PG_FUNCTION_ARGS)
{
Datum val = PG_GETARG_DATUM(0);
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
- JsonbInState result;
- JsonbTypeCategory tcategory;
- Oid outfuncoid;
+ JsonbValue *res = to_jsonb_worker(val, val_type);
+ PG_RETURN_POINTER(JsonbValueToJsonb(res));
+}
- if (val_type == InvalidOid)
+/*
+ * Do the actual conversion to jsonb for to_jsonb function. This logic is
+ * separated because it can be useful not only in here (e.g. we use it in
+ * jsonb subscripting)
+ */
+JsonbValue *
+to_jsonb_worker(Datum source, Oid source_type)
+{
+ JsonbInState result;
+ JsonbTypeCategory tcategory;
+ Oid outfuncoid;
+
+ if (source_type == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine input data type")));
- jsonb_categorize_type(val_type,
+ jsonb_categorize_type(source_type,
&tcategory, &outfuncoid);
memset(&result, 0, sizeof(JsonbInState));
- datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
-
- PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
+ datum_to_jsonb(source, false, &result, tcategory, outfuncoid, false);
+ return result.res;
}
/*
diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index 0d2abb3..26453ab 100644
--- a/src/backend/utils/adt/jsonb_util.c
+++ b/src/backend/utils/adt/jsonb_util.c
@@ -62,18 +62,29 @@ static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate,
JsonbIteratorToken seq,
JsonbValue *scalarVal);
+JsonbValue *
+JsonbToJsonbValue(Jsonb *jsonb)
+{
+ JsonbValue *val = (JsonbValue *) palloc(sizeof(JsonbValue));
+
+ val->type = jbvBinary;
+ val->val.binary.data = &jsonb->root;
+ val->val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
+
+ return val;
+}
+
/*
* Turn an in-memory JsonbValue into a Jsonb for on-disk storage.
*
- * There isn't a JsonbToJsonbValue(), because generally we find it more
- * convenient to directly iterate through the Jsonb representation and only
- * really convert nested scalar values. JsonbIteratorNext() does this, so that
- * clients of the iteration code don't have to directly deal with the binary
- * representation (JsonbDeepContains() is a notable exception, although all
- * exceptions are internal to this module). In general, functions that accept
- * a JsonbValue argument are concerned with the manipulation of scalar values,
- * or simple containers of scalar values, where it would be inconvenient to
- * deal with a great amount of other state.
+ * Generally we find it more convenient to directly iterate through the Jsonb
+ * representation and only really convert nested scalar values.
+ * JsonbIteratorNext() does this, so that clients of the iteration code don't
+ * have to directly deal with the binary representation (JsonbDeepContains() is
+ * a notable exception, although all exceptions are internal to this module).
+ * In general, functions that accept a JsonbValue argument are concerned with
+ * the manipulation of scalar values, or simple containers of scalar values,
+ * where it would be inconvenient to deal with a great amount of other state.
*/
Jsonb *
JsonbValueToJsonb(JsonbValue *val)
@@ -521,6 +532,30 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq,
JsonbValue *res = NULL;
JsonbValue v;
JsonbIteratorToken tok;
+ int i;
+
+ if (jbval && (seq == WJB_ELEM || seq == WJB_VALUE) && jbval->type == jbvObject)
+ {
+ pushJsonbValue(pstate, WJB_BEGIN_OBJECT, NULL);
+ for (i = 0; i < jbval->val.object.nPairs; i++)
+ {
+ pushJsonbValue(pstate, WJB_KEY, &jbval->val.object.pairs[i].key);
+ pushJsonbValue(pstate, WJB_VALUE, &jbval->val.object.pairs[i].value);
+ }
+
+ return pushJsonbValue(pstate, WJB_END_OBJECT, NULL);
+ }
+
+ if (jbval && (seq == WJB_ELEM || seq == WJB_VALUE) && jbval->type == jbvArray)
+ {
+ pushJsonbValue(pstate, WJB_BEGIN_ARRAY, NULL);
+ for (i = 0; i < jbval->val.array.nElems; i++)
+ {
+ pushJsonbValue(pstate, WJB_ELEM, &jbval->val.array.elems[i]);
+ }
+
+ return pushJsonbValue(pstate, WJB_END_ARRAY, NULL);
+ }
if (!jbval || (seq != WJB_ELEM && seq != WJB_VALUE) ||
jbval->type != jbvBinary)
@@ -531,9 +566,30 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq,
/* unpack the binary and add each piece to the pstate */
it = JsonbIteratorInit(jbval->val.binary.data);
+
+ if ((jbval->val.binary.data->header & JB_FSCALAR) && *pstate)
+ {
+ tok = JsonbIteratorNext(&it, &v, true);
+ Assert(tok == WJB_BEGIN_ARRAY);
+ Assert(v.type == jbvArray && v.val.array.rawScalar);
+
+ tok = JsonbIteratorNext(&it, &v, true);
+ Assert(tok == WJB_ELEM);
+
+ res = pushJsonbValueScalar(pstate, seq, &v);
+
+ tok = JsonbIteratorNext(&it, &v, true);
+ Assert(tok == WJB_END_ARRAY);
+ Assert(it == NULL);
+
+ return res;
+ }
+
while ((tok = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
res = pushJsonbValueScalar(pstate, tok,
- tok < WJB_BEGIN_ARRAY ? &v : NULL);
+ tok < WJB_BEGIN_ARRAY ||
+ (tok == WJB_BEGIN_ARRAY &&
+ v.val.array.rawScalar) ? &v : NULL);
return res;
}
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 3966e43..2ecf893 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -20,12 +20,16 @@
#include "catalog/pg_type.h"
#include "fmgr.h"
#include "funcapi.h"
+#include "executor/execExpr.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
+#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
+#include "utils/fmgroids.h"
#include "utils/json.h"
#include "utils/jsonapi.h"
#include "utils/jsonb.h"
@@ -33,6 +37,7 @@
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
+#include "parser/parse_node.h"
/* Operations available for setPath */
#define JB_PATH_CREATE 0x0001
@@ -449,18 +454,19 @@ static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container,
/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
JsonbParseState **state);
+static Datum jsonb_set_element(Datum datum, Datum *path, int path_len,
+ Datum sourceData, Oid source_type);
+static Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath,
+ bool *isnull, bool as_text);
static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems,
bool *path_nulls, int path_len,
- JsonbParseState **st, int level, Jsonb *newval,
- int op_type);
+ JsonbParseState **st, int level, JsonbValue *newval, int op_type);
static void setPathObject(JsonbIterator **it, Datum *path_elems,
bool *path_nulls, int path_len, JsonbParseState **st,
- int level,
- Jsonb *newval, uint32 npairs, int op_type);
+ int level, JsonbValue *newval, uint32 npairs, int op_type);
static void setPathArray(JsonbIterator **it, Datum *path_elems,
bool *path_nulls, int path_len, JsonbParseState **st,
- int level, Jsonb *newval, uint32 nelems, int op_type);
-static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb);
+ int level, JsonbValue *newval, uint32 nelems, int op_type);
/* function supporting iterate_json_string_values */
static void iterate_string_values_scalar(void *state, char *token, JsonTokenType tokentype);
@@ -1374,16 +1380,11 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
{
Jsonb *jb = PG_GETARG_JSONB(0);
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
- Jsonb *res;
Datum *pathtext;
bool *pathnulls;
+ bool isnull;
int npath;
- int i;
- bool have_object = false,
- have_array = false;
- JsonbValue *jbvp = NULL;
- JsonbValue tv;
- JsonbContainer *container;
+ Datum res;
/*
* If the array contains any null elements, return NULL, on the grounds
@@ -1398,9 +1399,28 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
deconstruct_array(path, TEXTOID, -1, false, 'i',
&pathtext, &pathnulls, &npath);
- /* Identify whether we have object, array, or scalar at top-level */
- container = &jb->root;
+ res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
+
+ if (isnull)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_DATUM(res);
+}
+static Datum
+jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
+{
+ Jsonb *res;
+ JsonbContainer *container = &jb->root;
+ JsonbValue *jbvp = NULL;
+ JsonbValue tv;
+ int i;
+ bool have_object = false,
+ have_array = false;
+
+ *isnull = false;
+
+ /* Identify whether we have object, array, or scalar at top-level */
if (JB_ROOT_IS_OBJECT(jb))
have_object = true;
else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
@@ -1425,14 +1445,14 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
{
if (as_text)
{
- PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL,
+ return PointerGetDatum(cstring_to_text(JsonbToCString(NULL,
container,
VARSIZE(jb))));
}
else
{
/* not text mode - just hand back the jsonb */
- PG_RETURN_JSONB(jb);
+ return JsonbGetDatum(jb);
}
}
@@ -1442,21 +1462,24 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
{
jbvp = findJsonbValueFromContainerLen(container,
JB_FOBJECT,
- VARDATA(pathtext[i]),
- VARSIZE(pathtext[i]) - VARHDRSZ);
+ VARDATA(path[i]),
+ VARSIZE(path[i]) - VARHDRSZ);
}
else if (have_array)
{
long lindex;
uint32 index;
- char *indextext = TextDatumGetCString(pathtext[i]);
+ char *indextext = TextDatumGetCString(path[i]);
char *endptr;
errno = 0;
lindex = strtol(indextext, &endptr, 10);
if (endptr == indextext || *endptr != '\0' || errno != 0 ||
lindex > INT_MAX || lindex < INT_MIN)
- PG_RETURN_NULL();
+ {
+ *isnull = true;
+ return PointerGetDatum(NULL);
+ }
if (lindex >= 0)
{
@@ -1474,7 +1497,10 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
nelements = JsonContainerSize(container);
if (-lindex > nelements)
- PG_RETURN_NULL();
+ {
+ *isnull = true;
+ return PointerGetDatum(NULL);
+ }
else
index = nelements + lindex;
}
@@ -1484,11 +1510,15 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
else
{
/* scalar, extraction yields a null */
- PG_RETURN_NULL();
+ *isnull = true;
+ return PointerGetDatum(NULL);
}
if (jbvp == NULL)
- PG_RETURN_NULL();
+ {
+ *isnull = true;
+ return PointerGetDatum(NULL);
+ }
else if (i == npath - 1)
break;
@@ -1513,27 +1543,57 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
{
/* special-case outputs for string and null values */
if (jbvp->type == jbvString)
- PG_RETURN_TEXT_P(cstring_to_text_with_len(jbvp->val.string.val,
- jbvp->val.string.len));
+ return PointerGetDatum(
+ cstring_to_text_with_len(jbvp->val.string.val,
+ jbvp->val.string.len));
if (jbvp->type == jbvNull)
- PG_RETURN_NULL();
+ {
+ *isnull = true;
+ return PointerGetDatum(NULL);
+ }
}
res = JsonbValueToJsonb(jbvp);
if (as_text)
{
- PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL,
+ return PointerGetDatum(cstring_to_text(JsonbToCString(NULL,
&res->root,
VARSIZE(res))));
}
else
{
/* not text mode - just hand back the jsonb */
- PG_RETURN_JSONB(res);
+ return JsonbGetDatum(res);
}
}
+Datum
+jsonb_set_element(Datum jsonbdatum, Datum *path, int path_len,
+ Datum sourceData, Oid source_type)
+{
+ Jsonb *jb = DatumGetJsonb(jsonbdatum);
+ JsonbValue *newval,
+ *res;
+ JsonbParseState *state = NULL;
+ JsonbIterator *it;
+ bool *path_nulls = palloc0(path_len * sizeof(bool));
+
+ newval = to_jsonb_worker(sourceData, source_type);
+
+ if (newval->type == jbvArray && newval->val.array.rawScalar)
+ *newval = newval->val.array.elems[0];
+
+ it = JsonbIteratorInit(&jb->root);
+
+ res = setPath(&it, path, path_nulls, path_len, &state, 0,
+ newval, JB_PATH_CREATE);
+
+ pfree(path_nulls);
+
+ PG_RETURN_JSONB(JsonbValueToJsonb(res));
+}
+
/*
* SQL function json_array_length(json) -> int
*/
@@ -3934,57 +3994,6 @@ jsonb_strip_nulls(PG_FUNCTION_ARGS)
}
/*
- * Add values from the jsonb to the parse state.
- *
- * If the parse state container is an object, the jsonb is pushed as
- * a value, not a key.
- *
- * This needs to be done using an iterator because pushJsonbValue doesn't
- * like getting jbvBinary values, so we can't just push jb as a whole.
- */
-static void
-addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb)
-{
- JsonbIterator *it;
- JsonbValue *o = &(*jbps)->contVal;
- JsonbValue v;
- JsonbIteratorToken type;
-
- it = JsonbIteratorInit(&jb->root);
-
- Assert(o->type == jbvArray || o->type == jbvObject);
-
- if (JB_ROOT_IS_SCALAR(jb))
- {
- (void) JsonbIteratorNext(&it, &v, false); /* skip array header */
- (void) JsonbIteratorNext(&it, &v, false); /* fetch scalar value */
-
- switch (o->type)
- {
- case jbvArray:
- (void) pushJsonbValue(jbps, WJB_ELEM, &v);
- break;
- case jbvObject:
- (void) pushJsonbValue(jbps, WJB_VALUE, &v);
- break;
- default:
- elog(ERROR, "unexpected parent of nested structure");
- }
- }
- else
- {
- while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
- {
- if (type == WJB_KEY || type == WJB_VALUE || type == WJB_ELEM)
- (void) pushJsonbValue(jbps, type, &v);
- else
- (void) pushJsonbValue(jbps, type, NULL);
- }
- }
-
-}
-
-/*
* SQL function jsonb_pretty (jsonb)
*
* Pretty-printed text for the jsonb
@@ -4256,7 +4265,8 @@ jsonb_set(PG_FUNCTION_ARGS)
{
Jsonb *in = PG_GETARG_JSONB(0);
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
- Jsonb *newval = PG_GETARG_JSONB(2);
+ Jsonb *newjsonb = PG_GETARG_JSONB(2);
+ JsonbValue *newval = JsonbToJsonbValue(newjsonb);
bool create = PG_GETARG_BOOL(3);
JsonbValue *res = NULL;
Datum *path_elems;
@@ -4348,7 +4358,8 @@ jsonb_insert(PG_FUNCTION_ARGS)
{
Jsonb *in = PG_GETARG_JSONB(0);
ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
- Jsonb *newval = PG_GETARG_JSONB(2);
+ Jsonb *newjsonb = PG_GETARG_JSONB(2);
+ JsonbValue *newval = JsonbToJsonbValue(newjsonb);
bool after = PG_GETARG_BOOL(3);
JsonbValue *res = NULL;
Datum *path_elems;
@@ -4511,7 +4522,7 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
static JsonbValue *
setPath(JsonbIterator **it, Datum *path_elems,
bool *path_nulls, int path_len,
- JsonbParseState **st, int level, Jsonb *newval, int op_type)
+ JsonbParseState **st, int level, JsonbValue *newval, int op_type)
{
JsonbValue v;
JsonbIteratorToken r;
@@ -4564,11 +4575,11 @@ setPath(JsonbIterator **it, Datum *path_elems,
static void
setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
int path_len, JsonbParseState **st, int level,
- Jsonb *newval, uint32 npairs, int op_type)
+ JsonbValue *newval, uint32 npairs, int op_type)
{
- JsonbValue v;
int i;
- JsonbValue k;
+ JsonbValue k,
+ v;
bool done = false;
if (level >= path_len || path_nulls[level])
@@ -4585,7 +4596,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
newkey.val.string.val = VARDATA_ANY(path_elems[level]);
(void) pushJsonbValue(st, WJB_KEY, &newkey);
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_VALUE, newval);
}
for (i = 0; i < npairs; i++)
@@ -4616,7 +4627,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
if (!(op_type & JB_PATH_DELETE))
{
(void) pushJsonbValue(st, WJB_KEY, &k);
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_VALUE, newval);
}
done = true;
}
@@ -4639,7 +4650,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
newkey.val.string.val = VARDATA_ANY(path_elems[level]);
(void) pushJsonbValue(st, WJB_KEY, &newkey);
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_VALUE, newval);
}
(void) pushJsonbValue(st, r, &k);
@@ -4671,7 +4682,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
static void
setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
int path_len, JsonbParseState **st, int level,
- Jsonb *newval, uint32 nelems, int op_type)
+ JsonbValue *newval, uint32 nelems, int op_type)
{
JsonbValue v;
int idx,
@@ -4719,7 +4730,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
(op_type & JB_PATH_CREATE_OR_INSERT))
{
Assert(newval != NULL);
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_ELEM, newval);
done = true;
}
@@ -4735,7 +4746,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
r = JsonbIteratorNext(it, &v, true); /* skip */
if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_ELEM, newval);
/*
* We should keep current value only in case of
@@ -4746,7 +4757,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
(void) pushJsonbValue(st, r, &v);
if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_ELEM, newval);
done = true;
}
@@ -4780,13 +4791,141 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
level == path_len - 1 && i == nelems - 1)
{
- addJsonbToParseState(st, newval);
+ (void) pushJsonbValue(st, WJB_ELEM, newval);
}
}
}
}
/*
+ * Perform an actual data extraction or modification for the jsonb
+ * subscripting. As a result the extracted Datum or the modified containers
+ * value will be returned.
+ */
+Datum
+jsonb_subscripting_fetch(PG_FUNCTION_ARGS)
+{
+ Datum containerSource = PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+ SubscriptingRefState *sbstate = step->d.sbsref.state;
+
+ return jsonb_get_element(DatumGetJsonb(containerSource),
+ sbstate->upper,
+ sbstate->numupper,
+ step->resnull,
+ false);
+}
+
+
+
+/*
+ * Perform an actual data extraction or modification for the jsonb
+ * subscripting. As a result the extracted Datum or the modified containers
+ * value will be returned.
+ */
+Datum
+jsonb_subscripting_assign(PG_FUNCTION_ARGS)
+{
+ Datum containerSource = PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+
+ SubscriptingRefState *sbstate = step->d.sbsref.state;
+ bool *is_null = step->resnull;
+ bool eisnull = sbstate->replacenull;
+
+ /*
+ * For an assignment to a fixed-length array type, both the original
+ * array and the value to be assigned into it must be non-NULL, else
+ * we punt and return the original array.
+ */
+ if (sbstate->refattrlength > 0) /* fixed-length array? */
+ if (eisnull || *is_null)
+ return containerSource;
+
+ /*
+ * 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 (*is_null)
+ {
+ containerSource =
+ PointerGetDatum(construct_empty_array(sbstate->refelemtype));
+ *is_null = false;
+ }
+
+ return jsonb_set_element(containerSource,
+ sbstate->upper,
+ sbstate->numupper,
+ sbstate->replacevalue,
+ sbstate->refelemtype);
+}
+
+/*
+ * Perform preparation for the jsonb subscripting. Since there are not any
+ * particular restrictions for this kind of subscripting, we will verify that
+ * it is not a slice operation. This function produces an expression that
+ * represents the result of extracting a single container element or the new
+ * container value with the source data inserted into the right part of the
+ * container.
+ */
+
+/*
+ * Handle jsonb-type subscripting logic.
+ */
+Datum
+jsonb_subscript_parse(PG_FUNCTION_ARGS)
+{
+ bool isAssignment = PG_GETARG_BOOL(0);
+ SubscriptingRef *sbsref = (SubscriptingRef *) PG_GETARG_POINTER(1);
+ ParseState *pstate = (ParseState *) PG_GETARG_POINTER(2);
+ List *upperIndexpr = NIL;
+ ListCell *l;
+
+ if (sbsref->reflowerindexpr != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("jsonb subscript does not support slices"),
+ parser_errposition(pstate, exprLocation(
+ ((Node *)lfirst(sbsref->reflowerindexpr->head))))));
+
+ foreach(l, sbsref->refupperindexpr)
+ {
+ Node *subexpr = (Node *) lfirst(l);
+
+ if (subexpr == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("jsonb subscript does not support slices"),
+ parser_errposition(pstate, exprLocation(
+ ((Node *) lfirst(sbsref->refupperindexpr->head))))));
+
+ subexpr = coerce_to_target_type(pstate,
+ subexpr, exprType(subexpr),
+ TEXTOID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (subexpr == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("jsonb subscript must have text type"),
+ parser_errposition(pstate, exprLocation(subexpr))));
+
+ upperIndexpr = lappend(upperIndexpr, subexpr);
+ }
+
+ sbsref->refupperindexpr = upperIndexpr;
+ if (isAssignment)
+ sbsref->refevalfunc = F_JSONB_SUBSCRIPTING_ASSIGN;
+ else
+ sbsref->refevalfunc = F_JSONB_SUBSCRIPTING_FETCH;
+
+ PG_RETURN_POINTER(sbsref);
+}
+
+/*
* Iterate over jsonb string values or elements, and pass them together with an
* iteration state to a specified JsonIterateStringValuesAction.
*/
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index cbde1ff..989f4fa 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -447,7 +447,7 @@ static void get_tablesample_def(TableSampleClause *tablesample,
static void get_opclass_name(Oid opclass, Oid actual_datatype,
StringInfo buf);
static Node *processIndirection(Node *node, deparse_context *context);
-static void printSubscripts(ArrayRef *aref, deparse_context *context);
+static void printSubscripts(SubscriptingRef *aref, deparse_context *context);
static char *get_relation_name(Oid relid);
static char *generate_relation_name(Oid relid, List *namespaces);
static char *generate_qualified_relation_name(Oid relid);
@@ -6175,7 +6175,7 @@ get_update_query_targetlist_def(Query *query, List *targetList,
{
/*
* We must dig down into the expr to see if it's a PARAM_MULTIEXPR
- * Param. That could be buried under FieldStores and ArrayRefs
+ * Param. That could be buried under FieldStores and SubscriptingRefs
* (cf processIndirection()), and underneath those there could be
* an implicit type coercion.
*/
@@ -6188,13 +6188,10 @@ get_update_query_targetlist_def(Query *query, List *targetList,
expr = (Node *) linitial(fstore->newvals);
}
- else if (IsA(expr, ArrayRef))
+ else if (IsA(expr, SubscriptingRef) && IsAssignment(expr))
{
- ArrayRef *aref = (ArrayRef *) expr;
-
- if (aref->refassgnexpr == NULL)
- break;
- expr = (Node *) aref->refassgnexpr;
+ SubscriptingRef *sbsref = (SubscriptingRef *) expr;
+ expr = (Node *) sbsref->refassgnexpr;
}
else
break;
@@ -7228,7 +7225,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
/* single words: always simple */
return true;
- case T_ArrayRef:
+ case T_SubscriptingRef:
case T_ArrayExpr:
case T_RowExpr:
case T_CoalesceExpr:
@@ -7345,7 +7342,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
return true; /* own parentheses */
}
case T_BoolExpr: /* lower precedence */
- case T_ArrayRef: /* other separators */
+ case T_SubscriptingRef: /* other separators */
case T_ArrayExpr: /* other separators */
case T_RowExpr: /* other separators */
case T_CoalesceExpr: /* own parentheses */
@@ -7395,7 +7392,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
return false;
return true; /* own parentheses */
}
- case T_ArrayRef: /* other separators */
+ case T_SubscriptingRef: /* other separators */
case T_ArrayExpr: /* other separators */
case T_RowExpr: /* other separators */
case T_CoalesceExpr: /* own parentheses */
@@ -7581,9 +7578,9 @@ get_rule_expr(Node *node, deparse_context *context,
get_windowfunc_expr((WindowFunc *) node, context);
break;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *aref = (ArrayRef *) node;
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
bool need_parens;
/*
@@ -7594,38 +7591,38 @@ get_rule_expr(Node *node, deparse_context *context,
* here too, and display only the assignment source
* expression.
*/
- if (IsA(aref->refexpr, CaseTestExpr))
+ if (IsA(sbsref->refexpr, CaseTestExpr))
{
- Assert(aref->refassgnexpr);
- get_rule_expr((Node *) aref->refassgnexpr,
+ Assert(sbsref->refassgnexpr);
+ get_rule_expr((Node *) sbsref->refassgnexpr,
context, showimplicit);
break;
}
/*
* Parenthesize the argument unless it's a simple Var or a
- * FieldSelect. (In particular, if it's another ArrayRef, we
+ * FieldSelect. (In particular, if it's another SubscriptingRef, we
* *must* parenthesize to avoid confusion.)
*/
- need_parens = !IsA(aref->refexpr, Var) &&
- !IsA(aref->refexpr, FieldSelect);
+ need_parens = !IsA(sbsref->refexpr, Var) &&
+ !IsA(sbsref->refexpr, FieldSelect);
if (need_parens)
appendStringInfoChar(buf, '(');
- get_rule_expr((Node *) aref->refexpr, context, showimplicit);
+ get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
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 "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.
+ */
Node *refassgnexpr;
/*
@@ -7640,8 +7637,8 @@ get_rule_expr(Node *node, deparse_context *context,
}
else
{
- /* Just an ordinary array fetch, so print subscripts */
- printSubscripts(aref, context);
+ /* Just an ordinary container fetch, so print subscripts */
+ printSubscripts(sbsref, context);
}
}
break;
@@ -7839,12 +7836,13 @@ get_rule_expr(Node *node, deparse_context *context,
bool need_parens;
/*
- * Parenthesize the argument unless it's an ArrayRef or
+ * Parenthesize the argument unless it's an SubscriptingRef or
* another FieldSelect. Note in particular that it would be
* WRONG to not parenthesize a Var argument; simplicity is not
* the issue here, having the right number of names is.
*/
- need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
+ need_parens = !IsA(arg, SubscriptingRef) &&
+ !IsA(arg, FieldSelect);
if (need_parens)
appendStringInfoChar(buf, '(');
get_rule_expr(arg, context, true);
@@ -10157,7 +10155,7 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
/*
* processIndirection - take care of array and subfield assignment
*
- * We strip any top-level FieldStore or assignment ArrayRef nodes that
+ * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
* appear in the input, printing them as decoration for the base column
* name (which we assume the caller just printed). Return the subexpression
* that's to be assigned.
@@ -10199,19 +10197,17 @@ processIndirection(Node *node, deparse_context *context)
*/
node = (Node *) linitial(fstore->newvals);
}
- else if (IsA(node, ArrayRef))
+ else if (IsA(node, SubscriptingRef) && IsAssignment(node))
{
- ArrayRef *aref = (ArrayRef *) node;
+ SubscriptingRef *sbsref = (SubscriptingRef *) node;
- if (aref->refassgnexpr == NULL)
- break;
- printSubscripts(aref, context);
+ printSubscripts(sbsref, context);
/*
* We ignore refexpr since it should be an uninteresting reference
* to the target column or subcolumn.
*/
- node = (Node *) aref->refassgnexpr;
+ node = (Node *) sbsref->refassgnexpr;
}
else
break;
@@ -10221,14 +10217,14 @@ processIndirection(Node *node, deparse_context *context)
}
static void
-printSubscripts(ArrayRef *aref, deparse_context *context)
+printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
{
StringInfo buf = context->buf;
ListCell *lowlist_item;
ListCell *uplist_item;
- lowlist_item = list_head(aref->reflowerindexpr); /* could be NULL */
- foreach(uplist_item, aref->refupperindexpr)
+ lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
+ foreach(uplist_item, sbsref->refupperindexpr)
{
appendStringInfoChar(buf, '[');
if (lowlist_item)
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 236d876..3655eef 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3094,3 +3094,23 @@ get_range_subtype(Oid rangeOid)
else
return InvalidOid;
}
+
+/*
+ * get_typsubsparse
+ *
+ * Given the type OID, return the type's typsubsparse procedure, if any.
+ */
+RegProcedure
+get_typsubsparse(Oid typid)
+{
+ HeapTuple tp;
+ RegProcedure result = InvalidOid;
+
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+ if (HeapTupleIsValid(tp))
+ {
+ result = ((Form_pg_type) GETSTRUCT(tp))->typsubsparse;
+ ReleaseSysCache(tp);
+ }
+ return result;
+}
diff --git a/src/include/c.h b/src/include/c.h
index fba07c6..08cf94b 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -422,6 +422,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.h b/src/include/catalog/pg_class.h
index 5a28883..4494831 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -147,7 +147,7 @@ typedef FormData_pg_class *Form_pg_class;
* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId;
* similarly, "1" in relminmxid stands for FirstMultiXactId
*/
-DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f f f t n f 3 1 _null_ _null_ _null_));
+DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 31 0 t f f f f f f t n f 3 1 _null_ _null_ _null_));
DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 22 0 f f f f f f f t n f 3 1 _null_ _null_ _null_));
DESCR("");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 82562ad..526a402 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -5456,6 +5456,21 @@ DESCR("pg_controldata recovery state information as a function");
DATA(insert OID = 3444 ( pg_control_init PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,23,23,23,23,23,23,23,16,16,23}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}" _null_ _null_ pg_control_init _null_ _null_ _null_ ));
DESCR("pg_controldata init state information as a function");
+/* type subscripting support */
+DATA(insert OID = 4001 ( jsonb_subscript_parse PGNSP PGUID 12 1 0 0 0 f f f f t f s s 3 0 "2281" "16 2281 2281" _null_ _null_ _null_ _null_ _null_ jsonb_subscript_parse _null_ _null_ _null_ ));
+DESCR("Jsonb subscripting logic");
+DATA(insert OID = 4002 ( jsonb_subscripting_fetch PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 "3802" "3802 2281" _null_ _null_ _null_ _null_ _null_ jsonb_subscripting_fetch _null_ _null_ _null_ ));
+DESCR("Jsonb subscripting logic");
+DATA(insert OID = 4003 ( jsonb_subscripting_assign PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 "3802" "3802 2281" _null_ _null_ _null_ _null_ _null_ jsonb_subscripting_assign _null_ _null_ _null_ ));
+DESCR("Jsonb subscripting logic");
+
+DATA(insert OID = 4004 ( array_subscript_parse PGNSP PGUID 12 1 0 0 0 f f f f t f s s 3 0 "2281" "16 2281 2281" _null_ _null_ _null_ _null_ _null_ array_subscript_parse _null_ _null_ _null_ ));
+DESCR("Array subscripting logic");
+DATA(insert OID = 4005 ( array_subscripting_fetch PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 "2283" "2277 2281" _null_ _null_ _null_ _null_ _null_ array_subscripting_fetch _null_ _null_ _null_ ));
+DESCR("Array subscripting logic");
+DATA(insert OID = 4006 ( array_subscripting_assign PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 "2277" "2277 2281" _null_ _null_ _null_ _null_ _null_ array_subscripting_assign _null_ _null_ _null_ ));
+DESCR("Array subscripting logic");
+
DATA(insert OID = 3445 ( pg_import_system_collations PGNSP PGUID 12 100 0 0 0 f f f f t f v r 2 0 2278 "16 4089" _null_ _null_ "{if_not_exists,schema}" _null_ _null_ pg_import_system_collations _null_ _null_ _null_ ));
DESCR("import collations from operating system");
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 345e916..e306767 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -199,6 +199,12 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
*/
Oid typcollation;
+ /*
+ * Type specific subscripting logic. If typsubsparse is none, it means
+ * that this type doesn't support subscripting.
+ */
+ regproc typsubsparse;
+
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/*
@@ -236,7 +242,7 @@ typedef FormData_pg_type *Form_pg_type;
* compiler constants for pg_type
* ----------------
*/
-#define Natts_pg_type 30
+#define Natts_pg_type 31
#define Anum_pg_type_typname 1
#define Anum_pg_type_typnamespace 2
#define Anum_pg_type_typowner 3
@@ -264,10 +270,10 @@ typedef FormData_pg_type *Form_pg_type;
#define Anum_pg_type_typtypmod 25
#define Anum_pg_type_typndims 26
#define Anum_pg_type_typcollation 27
-#define Anum_pg_type_typdefaultbin 28
-#define Anum_pg_type_typdefault 29
-#define Anum_pg_type_typacl 30
-
+#define Anum_pg_type_typsubsparse 28
+#define Anum_pg_type_typdefaultbin 29
+#define Anum_pg_type_typdefault 30
+#define Anum_pg_type_typacl 31
/* ----------------
* initial contents of pg_type
@@ -283,102 +289,102 @@ typedef FormData_pg_type *Form_pg_type;
*/
/* OIDS 1 - 99 */
-DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("boolean, 'true'/'false'");
#define BOOLOID 16
-DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("variable-length string, binary values escaped");
#define BYTEAOID 17
-DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("single character");
#define CHAROID 18
-DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("63-byte type for storing system identifiers");
#define NAMEOID 19
-DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("~18 digit integer, 8-byte storage");
#define INT8OID 20
-DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("-32 thousand to 32 thousand, 2-byte storage");
#define INT2OID 21
-DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("array of int2, used in system tables");
#define INT2VECTOROID 22
-DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("-2 billion to 2 billion integer, 4-byte storage");
#define INT4OID 23
-DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered procedure");
#define REGPROCOID 24
-DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 100 - _null_ _null_ _null_ ));
DESCR("variable-length string, no limit specified");
#define TEXTOID 25
-DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("object identifier(oid), maximum 4 billion");
#define OIDOID 26
-DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("(block, offset), physical location of tuple");
#define TIDOID 27
-DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("transaction id");
#define XIDOID 28
-DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("command identifier type, sequence in transaction id");
#define CIDOID 29
-DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("array of oids, used in system tables");
#define OIDVECTOROID 30
/* hand-built rowtype entries for bootstrapped catalogs */
/* NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations */
-DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
+DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
+DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
+DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
/* OIDS 100 - 199 */
-DATA(insert OID = 114 ( json PGNSP PGUID -1 f b U f t \054 0 0 199 json_in json_out json_recv json_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 114 ( json PGNSP PGUID -1 f b U f t \054 0 0 199 json_in json_out json_recv json_send - - - i x f 0 -1 0 0 - _null_ _null_ _null_ ));
#define JSONOID 114
-DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("XML content");
#define XMLOID 142
-DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 199 ( _json PGNSP PGUID -1 f b A f t \054 0 114 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 199 ( _json PGNSP PGUID -1 f b A f t \054 0 114 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
-DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 100 - _null_ _null_ _null_ ));
DESCR("string representing an internal node tree");
#define PGNODETREEOID 194
-DATA(insert OID = 3361 ( pg_ndistinct PGNSP PGUID -1 f b S f t \054 0 0 0 pg_ndistinct_in pg_ndistinct_out pg_ndistinct_recv pg_ndistinct_send - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 3361 ( pg_ndistinct PGNSP PGUID -1 f b S f t \054 0 0 0 pg_ndistinct_in pg_ndistinct_out pg_ndistinct_recv pg_ndistinct_send - - - i x f 0 -1 0 100 - _null_ _null_ _null_ ));
DESCR("multivariate ndistinct coefficients");
#define PGNDISTINCTOID 3361
-DATA(insert OID = 3402 ( pg_dependencies PGNSP PGUID -1 f b S f t \054 0 0 0 pg_dependencies_in pg_dependencies_out pg_dependencies_recv pg_dependencies_send - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 3402 ( pg_dependencies PGNSP PGUID -1 f b S f t \054 0 0 0 pg_dependencies_in pg_dependencies_out pg_dependencies_recv pg_dependencies_send - - - i x f 0 -1 0 100 - _null_ _null_ _null_ ));
DESCR("multivariate dependencies");
#define PGDEPENDENCIESOID 3402
-DATA(insert OID = 32 ( pg_ddl_command PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 pg_ddl_command_in pg_ddl_command_out pg_ddl_command_recv pg_ddl_command_send - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 32 ( pg_ddl_command PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 pg_ddl_command_in pg_ddl_command_out pg_ddl_command_recv pg_ddl_command_send - - - ALIGNOF_POINTER p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("internal type for passing CollectedCommand");
#define PGDDLCOMMANDOID 32
/* OIDS 200 - 299 */
-DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("storage manager");
/* OIDS 300 - 399 */
@@ -388,280 +394,280 @@ DESCR("storage manager");
/* OIDS 500 - 599 */
/* OIDS 600 - 699 */
-DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("geometric point '(x, y)'");
#define POINTOID 600
-DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("geometric line segment '(pt1,pt2)'");
#define LSEGOID 601
-DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("geometric path '(pt1,...)'");
#define PATHOID 602
-DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("geometric box '(lower left,upper right)'");
#define BOXOID 603
-DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("geometric polygon '(pt1,...)'");
#define POLYGONOID 604
-DATA(insert OID = 628 ( line PGNSP PGUID 24 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 628 ( line PGNSP PGUID 24 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
DESCR("geometric line");
#define LINEOID 628
-DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* OIDS 700 - 799 */
-DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("single-precision floating point number, 4-byte storage");
#define FLOAT4OID 700
-DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("double-precision floating point number, 8-byte storage");
#define FLOAT8OID 701
-DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("absolute, limited-range date and time (Unix system time)");
#define ABSTIMEOID 702
-DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("relative, limited-range time interval (Unix delta time)");
#define RELTIMEOID 703
-DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("(abstime,abstime), time interval");
#define TINTERVALOID 704
-DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f p X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f p X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("");
#define UNKNOWNOID 705
-DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("geometric circle '(center,radius)'");
#define CIRCLEOID 718
-DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("monetary amounts, $d,ddd.cc");
#define CASHOID 790
-DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* OIDS 800 - 899 */
-DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("XX:XX:XX:XX:XX:XX, MAC address");
#define MACADDROID 829
-DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("IP address/netmask, host address, netmask optional");
#define INETOID 869
-DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("network IP address/netmask, network address");
#define CIDROID 650
-DATA(insert OID = 774 ( macaddr8 PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 774 ( macaddr8 PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
#define MACADDR8OID 774
/* OIDS 900 - 999 */
/* OIDS 1000 - 1099 */
-DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define INT2ARRAYOID 1005
-DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define INT4ARRAYOID 1007
-DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 100 array_subscript_parse _null_ _null_ _null_ ));
#define TEXTARRAYOID 1009
-DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define OIDARRAYOID 1028
-DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
-DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
-DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b A f t \054 0 700 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout array_typanalyze i x f 0 -1 0 100 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout array_typanalyze i x f 0 -1 0 100 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b A f t \054 0 700 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define FLOAT4ARRAYOID 1021
-DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b A f t \054 0 701 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b A f t \054 0 702 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b A f t \054 0 701 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b A f t \054 0 702 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("access control list");
#define ACLITEMOID 1033
-DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b A f t \054 0 829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 775 ( _macaddr8 PGNSP PGUID -1 f b A f t \054 0 774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b A f t \054 0 869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b A f t \054 0 650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1263 ( _cstring PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b A f t \054 0 829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 775 ( _macaddr8 PGNSP PGUID -1 f b A f t \054 0 774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b A f t \054 0 869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b A f t \054 0 650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1263 ( _cstring PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define CSTRINGARRAYOID 1263
-DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b S f t \054 0 0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b S f t \054 0 0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 100 - _null_ _null_ _null_ ));
DESCR("char(length), blank-padded string, fixed storage length");
#define BPCHAROID 1042
-DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b S f t \054 0 0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b S f t \054 0 0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 100 - _null_ _null_ _null_ ));
DESCR("varchar(length), non-blank-padded string, variable storage length");
#define VARCHAROID 1043
-DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b D f t \054 0 0 1182 date_in date_out date_recv date_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b D f t \054 0 0 1182 date_in date_out date_recv date_send - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("date");
#define DATEOID 1082
-DATA(insert OID = 1083 ( time PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1083 ( time PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("time of day");
#define TIMEOID 1083
/* OIDS 1100 - 1199 */
-DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1115 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1115 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("date and time");
#define TIMESTAMPOID 1114
-DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b A f t \054 0 1114 0 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b A f t \054 0 1082 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b A f t \054 0 1083 0 array_in array_out array_recv array_send timetypmodin timetypmodout array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 FLOAT8PASSBYVAL b D t t \054 0 0 1185 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b A f t \054 0 1114 0 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b A f t \054 0 1082 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b A f t \054 0 1083 0 array_in array_out array_recv array_send timetypmodin timetypmodout array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 FLOAT8PASSBYVAL b D t t \054 0 0 1185 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("date and time with time zone");
#define TIMESTAMPTZOID 1184
-DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b A f t \054 0 1184 0 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b T t t \054 0 0 1187 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b A f t \054 0 1184 0 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b T t t \054 0 0 1187 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("@ <number> <units>, time interval");
#define INTERVALOID 1186
-DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b A f t \054 0 1186 0 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b A f t \054 0 1186 0 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* OIDS 1200 - 1299 */
-DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b A f t \054 0 1700 0 array_in array_out array_recv array_send numerictypmodin numerictypmodout array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b D f t \054 0 0 1270 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b A f t \054 0 1700 0 array_in array_out array_recv array_send numerictypmodin numerictypmodout array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b D f t \054 0 0 1270 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("time of day with time zone");
#define TIMETZOID 1266
-DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b A f t \054 0 1266 0 array_in array_out array_recv array_send timetztypmodin timetztypmodout array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b A f t \054 0 1266 0 array_in array_out array_recv array_send timetztypmodin timetztypmodout array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* OIDS 1500 - 1599 */
-DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b V f t \054 0 0 1561 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b V f t \054 0 0 1561 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("fixed-length bit string");
#define BITOID 1560
-DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b A f t \054 0 1560 0 array_in array_out array_recv array_send bittypmodin bittypmodout array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b V t t \054 0 0 1563 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b A f t \054 0 1560 0 array_in array_out array_recv array_send bittypmodin bittypmodout array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b V t t \054 0 0 1563 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("variable-length bit string");
#define VARBITOID 1562
-DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b A f t \054 0 1562 0 array_in array_out array_recv array_send varbittypmodin varbittypmodout array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b A f t \054 0 1562 0 array_in array_out array_recv array_send varbittypmodin varbittypmodout array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* OIDS 1600 - 1699 */
/* OIDS 1700 - 1799 */
-DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b N f t \054 0 0 1231 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b N f t \054 0 0 1231 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("numeric(precision, decimal), arbitrary precision number");
#define NUMERICOID 1700
-DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b U f t \054 0 0 2201 textin textout textrecv textsend - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b U f t \054 0 0 2201 textin textout textrecv textsend - - - i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("reference to cursor (portal name)");
#define REFCURSOROID 1790
/* OIDS 2200 - 2299 */
-DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b A f t \054 0 1790 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b A f t \054 0 1790 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
-DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b N f t \054 0 0 2207 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b N f t \054 0 0 2207 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered procedure (with args)");
#define REGPROCEDUREOID 2202
-DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b N f t \054 0 0 2208 regoperin regoperout regoperrecv regopersend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b N f t \054 0 0 2208 regoperin regoperout regoperrecv regopersend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered operator");
#define REGOPEROID 2203
-DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b N f t \054 0 0 2209 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b N f t \054 0 0 2209 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered operator (with args)");
#define REGOPERATOROID 2204
-DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b N f t \054 0 0 2210 regclassin regclassout regclassrecv regclasssend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b N f t \054 0 0 2210 regclassin regclassout regclassrecv regclasssend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered class");
#define REGCLASSOID 2205
-DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regtypein regtypeout regtyperecv regtypesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regtypein regtypeout regtyperecv regtypesend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered type");
#define REGTYPEOID 2206
-DATA(insert OID = 4096 ( regrole PGNSP PGUID 4 t b N f t \054 0 0 4097 regrolein regroleout regrolerecv regrolesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 4096 ( regrole PGNSP PGUID 4 t b N f t \054 0 0 4097 regrolein regroleout regrolerecv regrolesend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered role");
#define REGROLEOID 4096
-DATA(insert OID = 4089 ( regnamespace PGNSP PGUID 4 t b N f t \054 0 0 4090 regnamespacein regnamespaceout regnamespacerecv regnamespacesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 4089 ( regnamespace PGNSP PGUID 4 t b N f t \054 0 0 4090 regnamespacein regnamespaceout regnamespacerecv regnamespacesend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered namespace");
#define REGNAMESPACEOID 4089
-DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define REGTYPEARRAYOID 2211
-DATA(insert OID = 4097 ( _regrole PGNSP PGUID -1 f b A f t \054 0 4096 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 4090 ( _regnamespace PGNSP PGUID -1 f b A f t \054 0 4089 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 4097 ( _regrole PGNSP PGUID -1 f b A f t \054 0 4096 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 4090 ( _regnamespace PGNSP PGUID -1 f b A f t \054 0 4089 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* uuid */
-DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("UUID datatype");
#define UUIDOID 2950
-DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* pg_lsn */
-DATA(insert OID = 3220 ( pg_lsn PGNSP PGUID 8 FLOAT8PASSBYVAL b U f t \054 0 0 3221 pg_lsn_in pg_lsn_out pg_lsn_recv pg_lsn_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3220 ( pg_lsn PGNSP PGUID 8 FLOAT8PASSBYVAL b U f t \054 0 0 3221 pg_lsn_in pg_lsn_out pg_lsn_recv pg_lsn_send - - - d p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("PostgreSQL LSN datatype");
#define LSNOID 3220
-DATA(insert OID = 3221 ( _pg_lsn PGNSP PGUID -1 f b A f t \054 0 3220 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3221 ( _pg_lsn PGNSP PGUID -1 f b A f t \054 0 3220 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* text search */
-DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("text representation for text search");
#define TSVECTOROID 3614
-DATA(insert OID = 3642 ( gtsvector PGNSP PGUID -1 f b U f t \054 0 0 3644 gtsvectorin gtsvectorout - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3642 ( gtsvector PGNSP PGUID -1 f b U f t \054 0 0 3644 gtsvectorin gtsvectorout - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("GiST index internal text representation for text search");
#define GTSVECTOROID 3642
-DATA(insert OID = 3615 ( tsquery PGNSP PGUID -1 f b U f t \054 0 0 3645 tsqueryin tsqueryout tsqueryrecv tsquerysend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3615 ( tsquery PGNSP PGUID -1 f b U f t \054 0 0 3645 tsqueryin tsqueryout tsqueryrecv tsquerysend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("query representation for text search");
#define TSQUERYOID 3615
-DATA(insert OID = 3734 ( regconfig PGNSP PGUID 4 t b N f t \054 0 0 3735 regconfigin regconfigout regconfigrecv regconfigsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3734 ( regconfig PGNSP PGUID 4 t b N f t \054 0 0 3735 regconfigin regconfigout regconfigrecv regconfigsend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered text search configuration");
#define REGCONFIGOID 3734
-DATA(insert OID = 3769 ( regdictionary PGNSP PGUID 4 t b N f t \054 0 0 3770 regdictionaryin regdictionaryout regdictionaryrecv regdictionarysend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3769 ( regdictionary PGNSP PGUID 4 t b N f t \054 0 0 3770 regdictionaryin regdictionaryout regdictionaryrecv regdictionarysend - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("registered text search dictionary");
#define REGDICTIONARYOID 3769
-DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b A f t \054 0 3614 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b A f t \054 0 3642 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b A f t \054 0 3614 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b A f t \054 0 3642 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* jsonb */
-DATA(insert OID = 3802 ( jsonb PGNSP PGUID -1 f b U f t \054 0 0 3807 jsonb_in jsonb_out jsonb_recv jsonb_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3802 ( jsonb PGNSP PGUID -1 f b U f t \054 0 0 3807 jsonb_in jsonb_out jsonb_recv jsonb_send - - - i x f 0 -1 0 0 jsonb_subscript_parse _null_ _null_ _null_ ));
DESCR("Binary JSON");
#define JSONBOID 3802
-DATA(insert OID = 3807 ( _jsonb PGNSP PGUID -1 f b A f t \054 0 3802 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3807 ( _jsonb PGNSP PGUID -1 f b A f t \054 0 3802 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
-DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("txid snapshot");
-DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/* range types */
-DATA(insert OID = 3904 ( int4range PGNSP PGUID -1 f r R f t \054 0 0 3905 range_in range_out range_recv range_send - - range_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3904 ( int4range PGNSP PGUID -1 f r R f t \054 0 0 3905 range_in range_out range_recv range_send - - range_typanalyze i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("range of integers");
#define INT4RANGEOID 3904
-DATA(insert OID = 3905 ( _int4range PGNSP PGUID -1 f b A f t \054 0 3904 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3906 ( numrange PGNSP PGUID -1 f r R f t \054 0 0 3907 range_in range_out range_recv range_send - - range_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3905 ( _int4range PGNSP PGUID -1 f b A f t \054 0 3904 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3906 ( numrange PGNSP PGUID -1 f r R f t \054 0 0 3907 range_in range_out range_recv range_send - - range_typanalyze i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("range of numerics");
-DATA(insert OID = 3907 ( _numrange PGNSP PGUID -1 f b A f t \054 0 3906 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3908 ( tsrange PGNSP PGUID -1 f r R f t \054 0 0 3909 range_in range_out range_recv range_send - - range_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3907 ( _numrange PGNSP PGUID -1 f b A f t \054 0 3906 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3908 ( tsrange PGNSP PGUID -1 f r R f t \054 0 0 3909 range_in range_out range_recv range_send - - range_typanalyze d x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("range of timestamps without time zone");
-DATA(insert OID = 3909 ( _tsrange PGNSP PGUID -1 f b A f t \054 0 3908 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3910 ( tstzrange PGNSP PGUID -1 f r R f t \054 0 0 3911 range_in range_out range_recv range_send - - range_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3909 ( _tsrange PGNSP PGUID -1 f b A f t \054 0 3908 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3910 ( tstzrange PGNSP PGUID -1 f r R f t \054 0 0 3911 range_in range_out range_recv range_send - - range_typanalyze d x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("range of timestamps with time zone");
-DATA(insert OID = 3911 ( _tstzrange PGNSP PGUID -1 f b A f t \054 0 3910 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3912 ( daterange PGNSP PGUID -1 f r R f t \054 0 0 3913 range_in range_out range_recv range_send - - range_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3911 ( _tstzrange PGNSP PGUID -1 f b A f t \054 0 3910 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3912 ( daterange PGNSP PGUID -1 f r R f t \054 0 0 3913 range_in range_out range_recv range_send - - range_typanalyze i x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("range of dates");
-DATA(insert OID = 3913 ( _daterange PGNSP PGUID -1 f b A f t \054 0 3912 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 3926 ( int8range PGNSP PGUID -1 f r R f t \054 0 0 3927 range_in range_out range_recv range_send - - range_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3913 ( _daterange PGNSP PGUID -1 f b A f t \054 0 3912 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
+DATA(insert OID = 3926 ( int8range PGNSP PGUID -1 f r R f t \054 0 0 3927 range_in range_out range_recv range_send - - range_typanalyze d x f 0 -1 0 0 - _null_ _null_ _null_ ));
DESCR("range of bigints");
-DATA(insert OID = 3927 ( _int8range PGNSP PGUID -1 f b A f t \054 0 3926 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3927 ( _int8range PGNSP PGUID -1 f b A f t \054 0 3926 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
/*
* pseudo-types
@@ -676,41 +682,41 @@ DATA(insert OID = 3927 ( _int8range PGNSP PGUID -1 f b A f t \054 0 3926 0 arr
* but there is now support for it in records and arrays. Perhaps we should
* just treat it as a regular base type?
*/
-DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p P f t \054 0 0 2287 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p P f t \054 0 0 2287 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
#define RECORDOID 2249
-DATA(insert OID = 2287 ( _record PGNSP PGUID -1 f p P f t \054 0 2249 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2287 ( _record PGNSP PGUID -1 f p P f t \054 0 2249 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 array_subscript_parse _null_ _null_ _null_ ));
#define RECORDARRAYOID 2287
-DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p P f t \054 0 0 1263 cstring_in cstring_out cstring_recv cstring_send - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p P f t \054 0 0 1263 cstring_in cstring_out cstring_recv cstring_send - - - c p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define CSTRINGOID 2275
-DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p P f t \054 0 0 0 any_in any_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p P f t \054 0 0 0 any_in any_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define ANYOID 2276
-DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p P f t \054 0 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p P f t \054 0 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
#define ANYARRAYOID 2277
-DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void_out void_recv void_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void_out void_recv void_send - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define VOIDOID 2278
-DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define TRIGGEROID 2279
-DATA(insert OID = 3838 ( event_trigger PGNSP PGUID 4 t p P f t \054 0 0 0 event_trigger_in event_trigger_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3838 ( event_trigger PGNSP PGUID 4 t p P f t \054 0 0 0 event_trigger_in event_trigger_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define EVTTRIGGEROID 3838
-DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define LANGUAGE_HANDLEROID 2280
-DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define INTERNALOID 2281
-DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p P f t \054 0 0 0 opaque_in opaque_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p P f t \054 0 0 0 opaque_in opaque_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define OPAQUEOID 2282
-DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p P f t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p P f t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define ANYELEMENTOID 2283
-DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define ANYNONARRAYOID 2776
-DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define ANYENUMOID 3500
-DATA(insert OID = 3115 ( fdw_handler PGNSP PGUID 4 t p P f t \054 0 0 0 fdw_handler_in fdw_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3115 ( fdw_handler PGNSP PGUID 4 t p P f t \054 0 0 0 fdw_handler_in fdw_handler_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define FDW_HANDLEROID 3115
-DATA(insert OID = 325 ( index_am_handler PGNSP PGUID 4 t p P f t \054 0 0 0 index_am_handler_in index_am_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 325 ( index_am_handler PGNSP PGUID 4 t p P f t \054 0 0 0 index_am_handler_in index_am_handler_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define INDEX_AM_HANDLEROID 325
-DATA(insert OID = 3310 ( tsm_handler PGNSP PGUID 4 t p P f t \054 0 0 0 tsm_handler_in tsm_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3310 ( tsm_handler PGNSP PGUID 4 t p P f t \054 0 0 0 tsm_handler_in tsm_handler_out - - - - - i p f 0 -1 0 0 - _null_ _null_ _null_ ));
#define TSM_HANDLEROID 3310
-DATA(insert OID = 3831 ( anyrange PGNSP PGUID -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 3831 ( anyrange PGNSP PGUID -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 - _null_ _null_ _null_ ));
#define ANYRANGEOID 3831
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index 01f0956..a9dd116 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -52,7 +52,8 @@ extern ObjectAddress TypeCreate(Oid newTypeOid,
int32 typeMod,
int32 typNDims,
bool typeNotNull,
- Oid typeCollation);
+ Oid typeCollation,
+ Oid subscriptingProcedure);
extern void GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
@@ -70,6 +71,7 @@ extern void GenerateTypeDependencies(Oid typeNamespace,
bool isImplicitArray,
Oid baseType,
Oid typeCollation,
+ Oid subscriptingProcedure,
Node *defaultExpr,
bool rebuild);
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 86fdb33..373716f 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -17,7 +17,7 @@
#include "nodes/execnodes.h"
/* forward reference to avoid circularity */
-struct ArrayRefState;
+struct SubscriptingRefState;
/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
/* expression's interpreter has been initialized */
@@ -178,20 +178,20 @@ typedef enum ExprEvalOp
EEOP_FIELDSTORE_FORM,
/* Process an array subscript; short-circuit expression to NULL if NULL */
- EEOP_ARRAYREF_SUBSCRIPT,
+ EEOP_SBSREF_SUBSCRIPT,
/*
- * Compute old array element/slice when an ArrayRef assignment expression
- * contains ArrayRef/FieldStore subexpressions. Value is accessed using
+ * Compute old array element/slice when an SubscriptingRef assignment expression
+ * contains SubscriptingRef/FieldStore subexpressions. Value is accessed using
* the CaseTest mechanism.
*/
- EEOP_ARRAYREF_OLD,
+ EEOP_SBSREF_OLD,
- /* compute new value for ArrayRef assignment expression */
- EEOP_ARRAYREF_ASSIGN,
+ /* compute new value for SubscriptingRef assignment expression */
+ EEOP_SBSREF_ASSIGN,
- /* compute element/slice for ArrayRef fetch expression */
- EEOP_ARRAYREF_FETCH,
+ /* compute element/slice for SubscriptingRef fetch expression */
+ EEOP_SBSREF_FETCH,
/* evaluate value for CoerceToDomainValue */
EEOP_DOMAIN_TESTVAL,
@@ -459,22 +459,25 @@ typedef struct ExprEvalStep
int ncolumns;
} fieldstore;
- /* for EEOP_ARRAYREF_SUBSCRIPT */
+ /* for EEOP_SBSREF_SUBSCRIPT */
struct
{
/* too big to have inline */
- struct ArrayRefState *state;
+ struct SubscriptingRefState *state;
int off; /* 0-based index of this subscript */
bool isupper; /* is it upper or lower subscript? */
int jumpdone; /* jump here on null */
- } arrayref_subscript;
+ } sbsref_subscript;
- /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */
+ /* for EEOP_SBSREF_OLD / ASSIGN / FETCH */
struct
{
/* too big to have inline */
- struct ArrayRefState *state;
- } arrayref;
+ FmgrInfo *eval_finfo; /* function to evaluate subscript */
+ FmgrInfo *nested_finfo; /* function to handle nested assignment */
+
+ struct SubscriptingRefState *state;
+ } sbsref;
/* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */
struct
@@ -565,7 +568,7 @@ typedef struct ExprEvalStep
/* Non-inline data for array operations */
-typedef struct ArrayRefState
+typedef struct SubscriptingRefState
{
bool isassignment; /* is it assignment, or just fetch? */
@@ -578,13 +581,13 @@ typedef struct ArrayRefState
/* 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 upper[MAX_SUBSCRIPT_DEPTH];
/* similarly for lower indexes, if any */
int numlower;
- bool lowerprovided[MAXDIM];
- int lowerindex[MAXDIM];
+ bool lowerprovided[MAX_SUBSCRIPT_DEPTH];
+ Datum lower[MAX_SUBSCRIPT_DEPTH];
/* subscript expressions get evaluated into here */
Datum subscriptvalue;
@@ -594,11 +597,10 @@ 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;
-
+} SubscriptingRefState;
extern void ExecReadyInterpretedExpr(ExprState *state);
@@ -629,10 +631,10 @@ extern void ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern bool ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op);
-extern void ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op);
-extern void ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op);
-extern void ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op);
+extern bool ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op);
extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f289f3c..12b3f88 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -648,7 +648,6 @@ typedef struct WindowFuncExprState
int wfuncno; /* ID number for wfunc within its plan node */
} WindowFuncExprState;
-
/* ----------------
* SetExprState node
*
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index f59d719..acac66b 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -149,7 +149,7 @@ typedef enum NodeTag
T_Aggref,
T_GroupingFunc,
T_WindowFunc,
- T_ArrayRef,
+ T_SubscriptingRef,
T_FuncExpr,
T_NamedArgExpr,
T_OpExpr,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 86ec82e..19651ef 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
+ *
+ * An 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,27 +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 */
+ int32 reftypmod; /* typmod of the container (and elements too) */
+ Oid refcollid; /* OID of collation, or InvalidOid if none */
+ Oid refevalfunc; /* OID of type-specific subscripting function */
+ 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
@@ -751,7 +759,7 @@ typedef struct FieldSelect
*
* FieldStore represents the operation of modifying one field in a tuple
* value, yielding a new tuple value (the input is not touched!). Like
- * the assign case of ArrayRef, this is used to implement UPDATE of a
+ * the assign case of SubscriptingRef, this is used to implement UPDATE of a
* portion of a column.
*
* A single FieldStore can actually represent updates of several different
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 1035bad..c5561e5 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -264,12 +264,13 @@ 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,
+extern Oid transformArrayType(Oid *containerType, int32 *containerTypmod);
+
+extern Node *transformContainerSubscripts(ParseState *pstate,
+ Node *containerBase,
+ Oid containerType,
Oid elementType,
- int32 arrayTypMod,
+ int32 containerTypMod,
List *indirection,
Node *assignFrom);
extern Const *make_const(ParseState *pstate, Value *value, int location);
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h
index 411e158..1b10670 100644
--- a/src/include/utils/jsonb.h
+++ b/src/include/utils/jsonb.h
@@ -366,6 +366,7 @@ extern JsonbValue *pushJsonbValue(JsonbParseState **pstate,
extern JsonbIterator *JsonbIteratorInit(JsonbContainer *container);
extern JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val,
bool skipNested);
+extern JsonbValue *JsonbToJsonbValue(Jsonb *jsonb);
extern Jsonb *JsonbValueToJsonb(JsonbValue *val);
extern bool JsonbDeepContains(JsonbIterator **val,
JsonbIterator **mContained);
@@ -377,5 +378,6 @@ extern char *JsonbToCString(StringInfo out, JsonbContainer *in,
extern char *JsonbToCStringIndent(StringInfo out, JsonbContainer *in,
int estimated_len);
+extern JsonbValue *to_jsonb_worker(Datum source, Oid source_type);
#endif /* __JSONB_H__ */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 88629d9..d020bed 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -160,6 +160,7 @@ extern void free_attstatsslot(Oid atttype,
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_typsubsparse(Oid typid);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
/* type_is_array_domain accepts both plain arrays and domains over arrays */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 7a40c99..898bfc7 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -4714,7 +4714,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
/*
* Evaluate the subscripts, switch into left-to-right order.
- * Like the expression built by ExecInitArrayRef(), complain
+ * Like the expression built by ExecInitSubscriptingRef(), complain
* if any subscript is null.
*/
for (i = 0; i < nsubscripts; i++)
@@ -6471,9 +6471,9 @@ exec_simple_check_node(Node *node)
case T_Param:
return TRUE;
- case T_ArrayRef:
+ case T_SubscriptingRef:
{
- ArrayRef *expr = (ArrayRef *) node;
+ SubscriptingRef *expr = (SubscriptingRef *) node;
if (!exec_simple_check_node((Node *) expr->refupperindexpr))
return FALSE;
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index c730563..ee219ae 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -190,9 +190,9 @@ select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2];
--
-- check subscription corner cases
--
--- More subscripts than MAXDIMS(6)
-SELECT ('{}'::int[])[1][2][3][4][5][6][7];
-ERROR: number of array dimensions (7) exceeds the maximum allowed (6)
+-- More subscripts than MAXDIMS(12)
+SELECT ('{}'::int[])[1][2][3][4][5][6][7][8][9][10][11][12][13];
+ERROR: number of array dimensions (13) exceeds the maximum allowed (12)
-- NULL index yields NULL when selecting
SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL][1];
int4
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index f199eb4..7fda815 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -3942,6 +3942,214 @@ HINT: Try using the function jsonb_set to replace key value.
select jsonb_insert('{"a": {"b": "value"}}', '{a, b}', '"new_value"', true);
ERROR: cannot replace existing key
HINT: Try using the function jsonb_set to replace key value.
+-- jsonb subscript
+select ('123'::jsonb)['a'];
+ jsonb
+-------
+
+(1 row)
+
+select ('123'::jsonb)[0];
+ jsonb
+-------
+
+(1 row)
+
+select ('{"a": 1}'::jsonb)['a'];
+ jsonb
+-------
+ 1
+(1 row)
+
+select ('{"a": 1}'::jsonb)[0];
+ jsonb
+-------
+
+(1 row)
+
+select ('{"a": 1}'::jsonb)['not_exist'];
+ jsonb
+-------
+
+(1 row)
+
+select ('[1, "2", null]'::jsonb)['a'];
+ jsonb
+-------
+
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[0];
+ jsonb
+-------
+ 1
+(1 row)
+
+select ('[1, "2", null]'::jsonb)['1'];
+ jsonb
+-------
+ "2"
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[1.0];
+ jsonb
+-------
+
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[2];
+ jsonb
+-------
+ null
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[3];
+ jsonb
+-------
+
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[-2];
+ jsonb
+-------
+ "2"
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[1]['a'];
+ jsonb
+-------
+
+(1 row)
+
+select ('[1, "2", null]'::jsonb)[1][0];
+ jsonb
+-------
+
+(1 row)
+
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['b'];
+ jsonb
+-------
+ "c"
+(1 row)
+
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'];
+ jsonb
+-----------
+ [1, 2, 3]
+(1 row)
+
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'][1];
+ jsonb
+-------
+ 2
+(1 row)
+
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d']['a'];
+ jsonb
+-------
+
+(1 row)
+
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1'];
+ jsonb
+---------------
+ {"a2": "aaa"}
+(1 row)
+
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2'];
+ jsonb
+-------
+ "aaa"
+(1 row)
+
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']['a3'];
+ jsonb
+-------
+
+(1 row)
+
+select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1'];
+ jsonb
+-----------------------
+ ["aaa", "bbb", "ccc"]
+(1 row)
+
+select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1'][2];
+ jsonb
+-------
+ "ccc"
+(1 row)
+
+create TEMP TABLE test_jsonb_subscript (
+ id int,
+ test_json jsonb
+);
+insert into test_jsonb_subscript values
+(1, '{}'), -- empty jsonb
+(2, '{"key": "value"}'); -- jsonb with data
+-- update empty jsonb
+update test_jsonb_subscript set test_json['a'] = 1 where id = 1;
+select * from test_jsonb_subscript;
+ id | test_json
+----+------------------
+ 2 | {"key": "value"}
+ 1 | {"a": 1}
+(2 rows)
+
+-- update jsonb with some data
+update test_jsonb_subscript set test_json['a'] = 1 where id = 2;
+select * from test_jsonb_subscript;
+ id | test_json
+----+--------------------------
+ 1 | {"a": 1}
+ 2 | {"a": 1, "key": "value"}
+(2 rows)
+
+-- replace jsonb
+update test_jsonb_subscript set test_json['a'] = 'test';
+select * from test_jsonb_subscript;
+ id | test_json
+----+-------------------------------
+ 1 | {"a": "test"}
+ 2 | {"a": "test", "key": "value"}
+(2 rows)
+
+-- replace by object
+update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb;
+select * from test_jsonb_subscript;
+ id | test_json
+----+---------------------------------
+ 1 | {"a": {"b": 1}}
+ 2 | {"a": {"b": 1}, "key": "value"}
+(2 rows)
+
+-- replace by array
+update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb;
+select * from test_jsonb_subscript;
+ id | test_json
+----+----------------------------------
+ 1 | {"a": [1, 2, 3]}
+ 2 | {"a": [1, 2, 3], "key": "value"}
+(2 rows)
+
+-- use jsonb subscription in where clause
+select * from test_jsonb_subscript where test_json['key'] = '"value"';
+ id | test_json
+----+----------------------------------
+ 2 | {"a": [1, 2, 3], "key": "value"}
+(1 row)
+
+select * from test_jsonb_subscript where test_json['key_doesnt_exists'] = '"value"';
+ id | test_json
+----+-----------
+(0 rows)
+
+select * from test_jsonb_subscript where test_json['key'] = '"wrong_value"';
+ id | test_json
+----+-----------
+(0 rows)
+
-- jsonb to tsvector
select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
to_tsvector
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 25dd4e2..fb7a319 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -106,8 +106,8 @@ select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2];
--
-- check subscription corner cases
--
--- More subscripts than MAXDIMS(6)
-SELECT ('{}'::int[])[1][2][3][4][5][6][7];
+-- More subscripts than MAXDIMS(12)
+SELECT ('{}'::int[])[1][2][3][4][5][6][7][8][9][10][11][12][13];
-- NULL index yields NULL when selecting
SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL][1];
SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL:1][1];
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 57fff3b..86d4fe7 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -1031,6 +1031,65 @@ select jsonb_insert('{"a": {"b": "value"}}', '{a, c}', '"new_value"', true);
select jsonb_insert('{"a": {"b": "value"}}', '{a, b}', '"new_value"');
select jsonb_insert('{"a": {"b": "value"}}', '{a, b}', '"new_value"', true);
+-- jsonb subscript
+select ('123'::jsonb)['a'];
+select ('123'::jsonb)[0];
+select ('{"a": 1}'::jsonb)['a'];
+select ('{"a": 1}'::jsonb)[0];
+select ('{"a": 1}'::jsonb)['not_exist'];
+select ('[1, "2", null]'::jsonb)['a'];
+select ('[1, "2", null]'::jsonb)[0];
+select ('[1, "2", null]'::jsonb)['1'];
+select ('[1, "2", null]'::jsonb)[1.0];
+select ('[1, "2", null]'::jsonb)[2];
+select ('[1, "2", null]'::jsonb)[3];
+select ('[1, "2", null]'::jsonb)[-2];
+select ('[1, "2", null]'::jsonb)[1]['a'];
+select ('[1, "2", null]'::jsonb)[1][0];
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['b'];
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'];
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'][1];
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d']['a'];
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1'];
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2'];
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']['a3'];
+select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1'];
+select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1'][2];
+
+create TEMP TABLE test_jsonb_subscript (
+ id int,
+ test_json jsonb
+);
+
+insert into test_jsonb_subscript values
+(1, '{}'), -- empty jsonb
+(2, '{"key": "value"}'); -- jsonb with data
+
+-- update empty jsonb
+update test_jsonb_subscript set test_json['a'] = 1 where id = 1;
+select * from test_jsonb_subscript;
+
+-- update jsonb with some data
+update test_jsonb_subscript set test_json['a'] = 1 where id = 2;
+select * from test_jsonb_subscript;
+
+-- replace jsonb
+update test_jsonb_subscript set test_json['a'] = 'test';
+select * from test_jsonb_subscript;
+
+-- replace by object
+update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb;
+select * from test_jsonb_subscript;
+
+-- replace by array
+update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb;
+select * from test_jsonb_subscript;
+
+-- use jsonb subscription in where clause
+select * from test_jsonb_subscript where test_json['key'] = '"value"';
+select * from test_jsonb_subscript where test_json['key_doesnt_exists'] = '"value"';
+select * from test_jsonb_subscript where test_json['key'] = '"wrong_value"';
+
-- jsonb to tsvector
select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
diff --git a/src/tutorial/Makefile b/src/tutorial/Makefile
index 16dc390..0ead60c 100644
--- a/src/tutorial/Makefile
+++ b/src/tutorial/Makefile
@@ -13,8 +13,8 @@
#
#-------------------------------------------------------------------------
-MODULES = complex funcs
-DATA_built = advanced.sql basics.sql complex.sql funcs.sql syscat.sql
+MODULES = complex funcs subscripting
+DATA_built = advanced.sql basics.sql complex.sql funcs.sql syscat.sql subscripting.sql
ifdef NO_PGXS
subdir = src/tutorial
diff --git a/src/tutorial/subscripting.c b/src/tutorial/subscripting.c
new file mode 100644
index 0000000..bf47d23
--- /dev/null
+++ b/src/tutorial/subscripting.c
@@ -0,0 +1,172 @@
+/*
+ * src/tutorial/subscripting.c
+ *
+ ******************************************************************************
+ This file contains routines that can be bound to a Postgres backend and
+ called by the backend in the process of processing queries. The calling
+ format for these routines is dictated by Postgres architecture.
+******************************************************************************/
+
+#include "postgres.h"
+
+#include "catalog/pg_type.h"
+#include "executor/executor.h"
+#include "executor/execExpr.h"
+#include "nodes/nodeFuncs.h"
+#include "parser/parse_coerce.h"
+#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
+
+PG_MODULE_MAGIC;
+
+typedef struct Custom
+{
+ int first;
+ int second;
+} Custom;
+
+PG_FUNCTION_INFO_V1(custom_in);
+PG_FUNCTION_INFO_V1(custom_subscript_parse);
+PG_FUNCTION_INFO_V1(custom_subscripting_assign);
+PG_FUNCTION_INFO_V1(custom_subscripting_extract);
+
+/*****************************************************************************
+ * Input/Output functions
+ *****************************************************************************/
+
+Datum
+custom_in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ int firstValue,
+ secondValue;
+ Custom *result;
+
+ if (sscanf(str, " ( %d , %d )", &firstValue, &secondValue) != 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for complex: \"%s\"",
+ str)));
+
+
+ result = (Custom *) palloc(sizeof(Custom));
+ result->first = firstValue;
+ result->second = secondValue;
+ PG_RETURN_POINTER(result);
+}
+
+PG_FUNCTION_INFO_V1(custom_out);
+
+Datum
+custom_out(PG_FUNCTION_ARGS)
+{
+ Custom *custom = (Custom *) PG_GETARG_POINTER(0);
+ char *result;
+
+ result = psprintf("(%d, %d)", custom->first, custom->second);
+ PG_RETURN_CSTRING(result);
+}
+
+/*****************************************************************************
+ * Custom subscripting logic functions
+ *****************************************************************************/
+
+Datum
+custom_subscripting_assign(PG_FUNCTION_ARGS)
+{
+ Custom *containerSource = (Custom *) PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+
+ SubscriptingRefState *sbstate = step->d.sbsref.state;
+ int index;
+
+ if (sbstate->numupper != 1)
+ ereport(ERROR, (errmsg("custom does not support nested subscripting")));
+
+ index = DatumGetInt32(sbstate->upper[0]);
+
+ if (index == 1)
+ containerSource->first = DatumGetInt32(sbstate->replacevalue);
+ else
+ containerSource->second = DatumGetInt32(sbstate->replacevalue);
+
+ PG_RETURN_POINTER(containerSource);
+}
+
+
+Datum
+custom_subscripting_extract(PG_FUNCTION_ARGS)
+{
+ Custom *containerSource = (Custom *) PG_GETARG_DATUM(0);
+ ExprEvalStep *step = (ExprEvalStep *) PG_GETARG_POINTER(1);
+ SubscriptingRefState *sbstate = step->d.sbsref.state;
+
+ int index;
+
+ if (sbstate->numupper != 1)
+ ereport(ERROR, (errmsg("custom does not support nested subscripting")));
+
+ index = DatumGetInt32(sbstate->upper[0]);
+
+ if (index == 1)
+ PG_RETURN_INT32(containerSource->first);
+ else
+ PG_RETURN_INT32(containerSource->second);
+}
+
+Datum
+custom_subscript_parse(PG_FUNCTION_ARGS)
+{
+ bool isAssignment = PG_GETARG_BOOL(0);
+ SubscriptingRef *sbsref = (SubscriptingRef *) PG_GETARG_POINTER(1);
+ ParseState *pstate = (ParseState *) PG_GETARG_POINTER(2);
+ List *upperIndexpr = NIL;
+ ListCell *l;
+ Datum assign_proc = CStringGetTextDatum("custom_subscripting_assign");
+ Datum extract_proc = CStringGetTextDatum("custom_subscripting_extract");
+
+ if (sbsref->reflowerindexpr != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("custom subscript does not support slices"),
+ parser_errposition(pstate, exprLocation(
+ ((Node *)lfirst(sbsref->reflowerindexpr->head))))));
+
+ foreach(l, sbsref->refupperindexpr)
+ {
+ Node *subexpr = (Node *) lfirst(l);
+
+ Assert(subexpr != NULL);
+
+ if (subexpr == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("custom subscript does not support slices"),
+ parser_errposition(pstate, exprLocation(
+ ((Node *) lfirst(sbsref->refupperindexpr->head))))));
+
+ 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("custom subscript must have int type"),
+ parser_errposition(pstate, exprLocation(subexpr))));
+
+ upperIndexpr = lappend(upperIndexpr, subexpr);
+ }
+
+ sbsref->refupperindexpr = upperIndexpr;
+ sbsref->refelemtype = INT4OID;
+
+ if (isAssignment)
+ sbsref->refevalfunc = DirectFunctionCall1(to_regproc, assign_proc);
+ else
+ sbsref->refevalfunc = DirectFunctionCall1(to_regproc, extract_proc);
+
+ PG_RETURN_POINTER(sbsref);
+}
diff --git a/src/tutorial/subscripting.source b/src/tutorial/subscripting.source
new file mode 100644
index 0000000..8182229
--- /dev/null
+++ b/src/tutorial/subscripting.source
@@ -0,0 +1,81 @@
+---------------------------------------------------------------------------
+--
+-- subscripting.sql-
+-- This file shows how to create a new subscripting procedure for
+-- user-defined type.
+--
+--
+-- Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+-- Portions Copyright (c) 1994, Regents of the University of California
+--
+-- src/tutorial/subscripting.source
+--
+---------------------------------------------------------------------------
+
+-----------------------------
+-- Creating a new type:
+-- We are going to create a new type called 'complex' which represents
+-- complex numbers.
+-- A user-defined type must have an input and an output function, and
+-- optionally can have binary input and output functions. All of these
+-- are usually user-defined C functions.
+-----------------------------
+
+-- Assume the user defined functions are in /home/erthalion/programms/postgresql-master/src/tutorial/complex$DLSUFFIX
+-- (we do not want to assume this is in the dynamic loader search path).
+-- Look at $PWD/complex.c for the source. Note that we declare all of
+-- them as STRICT, so we do not need to cope with NULL inputs in the
+-- C code. We also mark them IMMUTABLE, since they always return the
+-- same outputs given the same inputs.
+
+-- the input function 'complex_in' takes a null-terminated string (the
+-- textual representation of the type) and turns it into the internal
+-- (in memory) representation. You will get a message telling you 'complex'
+-- does not exist yet but that's okay.
+
+CREATE FUNCTION custom_in(cstring)
+ RETURNS custom
+ AS '_OBJWD_/subscripting'
+ LANGUAGE C IMMUTABLE STRICT;
+
+-- the output function 'complex_out' takes the internal representation and
+-- converts it into the textual representation.
+
+CREATE FUNCTION custom_out(custom)
+ RETURNS cstring
+ AS '_OBJWD_/subscripting'
+ LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION custom_subscript_parse(internal)
+ RETURNS internal
+ AS '_OBJWD_/subscripting'
+ LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION custom_subscripting_extract(internal)
+ RETURNS internal
+ AS '_OBJWD_/subscripting'
+ LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION custom_subscripting_assign(internal)
+ RETURNS internal
+ AS '_OBJWD_/subscripting'
+ LANGUAGE C IMMUTABLE STRICT;
+
+CREATE TYPE custom (
+ internallength = 8,
+ input = custom_in,
+ output = custom_out,
+ subscripting = custom_subscript_parse
+);
+
+-- we can use it in a table
+
+CREATE TABLE test_subscripting (
+ data custom
+);
+
+INSERT INTO test_subscripting VALUES ('(1, 2)');
+
+SELECT data[0] from test_subscripting;
+
+UPDATE test_subscripting SET data[1] = 3;