plpgsql-parser-reftype-array.patch
text/x-patch
Filename: plpgsql-parser-reftype-array.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/pl_comp.c | 23 | 0 |
| src/pl/plpgsql/src/pl_gram.y | 44 | 13 |
| src/pl/plpgsql/src/plpgsql.h | 1 | 0 |
commit 3418f61191fe4b377717451b929cefb8028d3718
Author: okbob@github.com <pavel.stehule@gmail.com>
Date: Mon Nov 20 08:49:41 2023 +0100
poc
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index a341cde2c1..83e91d82d5 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -2095,6 +2095,29 @@ plpgsql_build_datatype(Oid typeOid, int32 typmod,
return typ;
}
+/*
+ * Returns an array for type specified as argument.
+ */
+PLpgSQL_type *
+plpgsql_datatype_arrayof(PLpgSQL_type *dtype)
+{
+ Oid array_typeid;
+
+ if (dtype->typisarray)
+ return dtype;
+
+ array_typeid = get_array_type(dtype->typoid);
+
+ if (!OidIsValid(dtype->typoid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(dtype->typoid))));
+
+ return plpgsql_build_datatype(array_typeid, dtype->atttypmod,
+ dtype->collation, NULL);
+}
+
/*
* Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
* and additional details (see comments for plpgsql_build_datatype).
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 6a09bfdd67..4784e8fd5c 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -2789,7 +2789,7 @@ read_datatype(int tok)
StringInfoData ds;
char *type_name;
int startlocation;
- PLpgSQL_type *result;
+ PLpgSQL_type *result = NULL;
int parenlevel = 0;
/* Should only be called while parsing DECLARE sections */
@@ -2817,15 +2817,11 @@ read_datatype(int tok)
K_TYPE, "type"))
{
result = plpgsql_parse_wordtype(dtname);
- if (result)
- return result;
}
else if (tok_is_keyword(tok, &yylval,
K_ROWTYPE, "rowtype"))
{
result = plpgsql_parse_wordrowtype(dtname);
- if (result)
- return result;
}
}
}
@@ -2841,15 +2837,11 @@ read_datatype(int tok)
K_TYPE, "type"))
{
result = plpgsql_parse_wordtype(dtname);
- if (result)
- return result;
}
else if (tok_is_keyword(tok, &yylval,
K_ROWTYPE, "rowtype"))
{
result = plpgsql_parse_wordrowtype(dtname);
- if (result)
- return result;
}
}
}
@@ -2865,19 +2857,58 @@ read_datatype(int tok)
K_TYPE, "type"))
{
result = plpgsql_parse_cwordtype(dtnames);
- if (result)
- return result;
}
else if (tok_is_keyword(tok, &yylval,
K_ROWTYPE, "rowtype"))
{
result = plpgsql_parse_cwordrowtype(dtnames);
- if (result)
- return result;
}
}
}
+ /* Array declaration can follow, but we check it only for known type */
+ if (result)
+ {
+ bool be_array = false;
+
+ tok = yylex();
+
+ /*
+ * SQL syntax allows multiple [] [ iconst ], ARRAY, ARRAY [ ]
+ * or ARRAY [ icons ]. Should we support all? It is not too hard.
+ */
+ if (tok_is_keyword(tok, &yylval,
+ K_ARRAY, "array"))
+ {
+ be_array = true;
+ tok = yylex();
+ }
+
+ if (tok == '[')
+ {
+ be_array = true;
+
+ while (tok == '[')
+ {
+ tok = yylex();
+ if (tok == ICONST)
+ tok = yylex();
+
+ if (tok != ']')
+ yyerror("syntax error, expected \"]\"");
+
+ tok = yylex();
+ }
+ }
+
+ plpgsql_push_back_token(tok);
+
+ if (be_array)
+ result = plpgsql_datatype_arrayof(result);
+
+ return result;
+ }
+
while (tok != ';')
{
if (tok == 0)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 9f0a912115..9da5e5b225 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1249,6 +1249,7 @@ extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents);
extern PGDLLEXPORT PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod,
Oid collation,
TypeName *origtypname);
+extern PLpgSQL_type *plpgsql_datatype_arrayof(PLpgSQL_type *dtype);
extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
PLpgSQL_type *dtype,
bool add2namespace);