v1-0002-add-sql-support.patch
text/x-diff
Filename: v1-0002-add-sql-support.patch
Type: text/x-diff
Part: 2
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
Series: patch v1-0002
| File | + | − |
|---|---|---|
| doc/src/sgml/keywords.sgml | 7 | 0 |
| doc/src/sgml/ref/alter_function.sgml | 19 | 0 |
| doc/src/sgml/ref/create_function.sgml | 14 | 0 |
| src/backend/catalog/pg_aggregate.c | 1 | 0 |
| src/backend/catalog/pg_depend.c | 36 | 16 |
| src/backend/catalog/pg_proc.c | 11 | 1 |
| src/backend/commands/functioncmds.c | 85 | 3 |
| src/backend/commands/proclang.c | 3 | 0 |
| src/backend/commands/typecmds.c | 1 | 0 |
| src/backend/parser/gram.y | 6 | 1 |
| src/backend/utils/adt/ruleutils.c | 15 | 0 |
| src/bin/pg_dump/pg_dump.c | 36 | 3 |
| src/bin/pg_dump/t/002_pg_dump.pl | 14 | 0 |
| src/include/catalog/pg_proc.h | 1 | 0 |
| src/include/parser/kwlist.h | 1 | 0 |
| src/test/regress/expected/alter_table.out | 2 | 3 |
| src/test/regress/sql/alter_table.sql | 2 | 3 |
diff --git a/doc/src/sgml/keywords.sgml b/doc/src/sgml/keywords.sgml
index a37d0b7..fa32a88 100644
--- a/doc/src/sgml/keywords.sgml
+++ b/doc/src/sgml/keywords.sgml
@@ -4522,6 +4522,13 @@
<entry>reserved</entry>
</row>
<row>
+ <entry><token>SUPPORT</token></entry>
+ <entry>non-reserved</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
<entry><token>SYMMETRIC</token></entry>
<entry>reserved</entry>
<entry>reserved</entry>
diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml
index d8747e0..03ffa59 100644
--- a/doc/src/sgml/ref/alter_function.sgml
+++ b/doc/src/sgml/ref/alter_function.sgml
@@ -40,6 +40,7 @@ ALTER FUNCTION <replaceable>name</replaceable> [ ( [ [ <replaceable class="param
PARALLEL { UNSAFE | RESTRICTED | SAFE }
COST <replaceable class="parameter">execution_cost</replaceable>
ROWS <replaceable class="parameter">result_rows</replaceable>
+ SUPPORT <replaceable class="parameter">support_function</replaceable>
SET <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
SET <replaceable class="parameter">configuration_parameter</replaceable> FROM CURRENT
RESET <replaceable class="parameter">configuration_parameter</replaceable>
@@ -248,6 +249,24 @@ ALTER FUNCTION <replaceable>name</replaceable> [ ( [ [ <replaceable class="param
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>SUPPORT</literal> <replaceable class="parameter">support_function</replaceable></term>
+
+ <listitem>
+ <para>
+ Set or change the planner support function to use for this function.
+ See <xref linkend="xfunc-optimization"/> for details. You must be
+ superuser to use this option.
+ </para>
+
+ <para>
+ This option cannot be used to remove the support function altogether,
+ since it must name a new support function. Use <command>CREATE OR
+ REPLACE FUNCTION</command> if you need to do that.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><replaceable>configuration_parameter</replaceable></term>
<term><replaceable>value</replaceable></term>
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index 4072543..dd6a2f7 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -33,6 +33,7 @@ CREATE [ OR REPLACE ] FUNCTION
| PARALLEL { UNSAFE | RESTRICTED | SAFE }
| COST <replaceable class="parameter">execution_cost</replaceable>
| ROWS <replaceable class="parameter">result_rows</replaceable>
+ | SUPPORT <replaceable class="parameter">support_function</replaceable>
| SET <replaceable class="parameter">configuration_parameter</replaceable> { TO <replaceable class="parameter">value</replaceable> | = <replaceable class="parameter">value</replaceable> | FROM CURRENT }
| AS '<replaceable class="parameter">definition</replaceable>'
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
@@ -478,6 +479,19 @@ CREATE [ OR REPLACE ] FUNCTION
</varlistentry>
<varlistentry>
+ <term><literal>SUPPORT</literal> <replaceable class="parameter">support_function</replaceable></term>
+
+ <listitem>
+ <para>
+ The name (optionally schema-qualified) of a <firstterm>planner support
+ function</firstterm> to use for this function. See
+ <xref linkend="xfunc-optimization"/> for details.
+ You must be superuser to use this option.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable>configuration_parameter</replaceable></term>
<term><replaceable>value</replaceable></term>
<listitem>
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index cc3806e..19e3171 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -632,6 +632,7 @@ AggregateCreate(const char *aggName,
parameterDefaults, /* parameterDefaults */
PointerGetDatum(NULL), /* trftypes */
PointerGetDatum(NULL), /* proconfig */
+ InvalidOid, /* no prosupport */
1, /* procost */
0); /* prorows */
procOid = myself.objectId;
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 2b8f651..23b01f8 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -286,9 +286,12 @@ deleteDependencyRecordsForClass(Oid classId, Oid objectId,
* newRefObjectId is the new referenced object (must be of class refClassId).
*
* Note the lack of objsubid parameters. If there are subobject references
- * they will all be readjusted.
+ * they will all be readjusted. Also, there is an expectation that we are
+ * dealing with NORMAL dependencies: if we have to replace an (implicit)
+ * dependency on a pinned object with an explicit dependency on an unpinned
+ * one, the new one will be NORMAL.
*
- * Returns the number of records updated.
+ * Returns the number of records updated -- zero indicates a problem.
*/
long
changeDependencyFor(Oid classId, Oid objectId,
@@ -301,35 +304,52 @@ changeDependencyFor(Oid classId, Oid objectId,
SysScanDesc scan;
HeapTuple tup;
ObjectAddress objAddr;
+ ObjectAddress depAddr;
+ bool oldIsPinned;
bool newIsPinned;
depRel = table_open(DependRelationId, RowExclusiveLock);
/*
- * If oldRefObjectId is pinned, there won't be any dependency entries on
- * it --- we can't cope in that case. (This isn't really worth expending
- * code to fix, in current usage; it just means you can't rename stuff out
- * of pg_catalog, which would likely be a bad move anyway.)
+ * Check to see if either oldRefObjectId or newRefObjectId is pinned.
+ * Pinned objects should not have any dependency entries pointing to them,
+ * so in these cases we should add or remove a pg_depend entry, or do
+ * nothing at all, rather than update an entry as in the normal case.
*/
objAddr.classId = refClassId;
objAddr.objectId = oldRefObjectId;
objAddr.objectSubId = 0;
- if (isObjectPinned(&objAddr, depRel))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot remove dependency on %s because it is a system object",
- getObjectDescription(&objAddr))));
+ oldIsPinned = isObjectPinned(&objAddr, depRel);
- /*
- * We can handle adding a dependency on something pinned, though, since
- * that just means deleting the dependency entry.
- */
objAddr.objectId = newRefObjectId;
newIsPinned = isObjectPinned(&objAddr, depRel);
- /* Now search for dependency records */
+ if (oldIsPinned)
+ {
+ table_close(depRel, RowExclusiveLock);
+
+ /*
+ * If both are pinned, we need do nothing. However, return 1 not 0,
+ * else callers will think this is an error case.
+ */
+ if (newIsPinned)
+ return 1;
+
+ /*
+ * There is no old dependency record, but we should insert a new one.
+ * Assume a normal dependency is wanted.
+ */
+ depAddr.classId = classId;
+ depAddr.objectId = objectId;
+ depAddr.objectSubId = 0;
+ recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
+
+ return 1;
+ }
+
+ /* There should be existing dependency record(s), so search. */
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
BTEqualStrategyNumber, F_OIDEQ,
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 3a86f1e..557e0ea 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,6 +88,7 @@ ProcedureCreate(const char *procedureName,
List *parameterDefaults,
Datum trftypes,
Datum proconfig,
+ Oid prosupport,
float4 procost,
float4 prorows)
{
@@ -319,7 +320,7 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
- values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(InvalidOid);
+ values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(prosupport);
values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind);
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
@@ -656,6 +657,15 @@ ProcedureCreate(const char *procedureName,
recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
NIL, DEPENDENCY_NORMAL);
+ /* dependency on support function, if any */
+ if (OidIsValid(prosupport))
+ {
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = prosupport;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
+
/* dependency on owner */
if (!is_update)
recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index eae2b09..4b13fdb 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -480,6 +480,7 @@ compute_common_attribute(ParseState *pstate,
List **set_items,
DefElem **cost_item,
DefElem **rows_item,
+ DefElem **support_item,
DefElem **parallel_item)
{
if (strcmp(defel->defname, "volatility") == 0)
@@ -538,6 +539,15 @@ compute_common_attribute(ParseState *pstate,
*rows_item = defel;
}
+ else if (strcmp(defel->defname, "support") == 0)
+ {
+ if (is_procedure)
+ goto procedure_error;
+ if (*support_item)
+ goto duplicate_error;
+
+ *support_item = defel;
+ }
else if (strcmp(defel->defname, "parallel") == 0)
{
if (is_procedure)
@@ -636,6 +646,45 @@ update_proconfig_value(ArrayType *a, List *set_items)
return a;
}
+static Oid
+interpret_func_support(DefElem *defel)
+{
+ List *procName = defGetQualifiedName(defel);
+ Oid procOid;
+ Oid argList[1];
+
+ /*
+ * Support 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("support function %s must return type %s",
+ NameListToString(procName), "internal")));
+
+ /*
+ * Someday we might want an ACL check here; but for now, we insist that
+ * you be superuser to specify a support function, so privilege on the
+ * support function is moot.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to specify a support function")));
+
+ return procOid;
+}
+
/*
* Dissect the list of options assembled in gram.y into function
@@ -656,6 +705,7 @@ compute_function_attributes(ParseState *pstate,
ArrayType **proconfig,
float4 *procost,
float4 *prorows,
+ Oid *prosupport,
char *parallel_p)
{
ListCell *option;
@@ -670,6 +720,7 @@ compute_function_attributes(ParseState *pstate,
List *set_items = NIL;
DefElem *cost_item = NULL;
DefElem *rows_item = NULL;
+ DefElem *support_item = NULL;
DefElem *parallel_item = NULL;
foreach(option, options)
@@ -727,6 +778,7 @@ compute_function_attributes(ParseState *pstate,
&set_items,
&cost_item,
&rows_item,
+ &support_item,
¶llel_item))
{
/* recognized common option */
@@ -789,6 +841,8 @@ compute_function_attributes(ParseState *pstate,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS must be positive")));
}
+ if (support_item)
+ *prosupport = interpret_func_support(support_item);
if (parallel_item)
*parallel_p = interpret_func_parallel(parallel_item);
}
@@ -894,6 +948,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
ArrayType *proconfig;
float4 procost;
float4 prorows;
+ Oid prosupport;
HeapTuple languageTuple;
Form_pg_language languageStruct;
List *as_clause;
@@ -918,6 +973,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
proconfig = NULL;
procost = -1; /* indicates not set */
prorows = -1; /* indicates not set */
+ prosupport = InvalidOid;
parallel = PROPARALLEL_UNSAFE;
/* Extract non-default attributes from stmt->options list */
@@ -927,7 +983,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
&as_clause, &language, &transformDefElem,
&isWindowFunc, &volatility,
&isStrict, &security, &isLeakProof,
- &proconfig, &procost, &prorows, ¶llel);
+ &proconfig, &procost, &prorows,
+ &prosupport, ¶llel);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
@@ -1114,6 +1171,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
parameterDefaults,
PointerGetDatum(trftypes),
PointerGetDatum(proconfig),
+ prosupport,
procost,
prorows);
}
@@ -1188,6 +1246,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
List *set_items = NIL;
DefElem *cost_item = NULL;
DefElem *rows_item = NULL;
+ DefElem *support_item = NULL;
DefElem *parallel_item = NULL;
ObjectAddress address;
@@ -1195,6 +1254,8 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
+ ObjectAddressSet(address, ProcedureRelationId, funcOid);
+
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
@@ -1229,6 +1290,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
&set_items,
&cost_item,
&rows_item,
+ &support_item,
¶llel_item) == false)
elog(ERROR, "option \"%s\" not recognized", defel->defname);
}
@@ -1267,6 +1329,28 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS is not applicable when function does not return a set")));
}
+ if (support_item)
+ {
+ /* interpret_func_support handles the privilege check */
+ Oid newsupport = interpret_func_support(support_item);
+
+ /* Add or replace dependency on support function */
+ if (OidIsValid(procForm->prosupport))
+ changeDependencyFor(ProcedureRelationId, funcOid,
+ ProcedureRelationId, procForm->prosupport,
+ newsupport);
+ else
+ {
+ ObjectAddress referenced;
+
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = newsupport;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
+ }
+
+ procForm->prosupport = newsupport;
+ }
if (set_items)
{
Datum datum;
@@ -1309,8 +1393,6 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
- ObjectAddressSet(address, ProcedureRelationId, funcOid);
-
table_close(rel, NoLock);
heap_freetuple(tup);
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index c2e9e41..59c4e8d 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,6 +141,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
NIL,
PointerGetDatum(NULL),
PointerGetDatum(NULL),
+ InvalidOid,
1,
0);
handlerOid = tmpAddr.objectId;
@@ -180,6 +181,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
NIL,
PointerGetDatum(NULL),
PointerGetDatum(NULL),
+ InvalidOid,
1,
0);
inlineOid = tmpAddr.objectId;
@@ -222,6 +224,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
NIL,
PointerGetDatum(NULL),
PointerGetDatum(NULL),
+ InvalidOid,
1,
0);
valOid = tmpAddr.objectId;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 35a6485..b0a61a3 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1664,6 +1664,7 @@ makeRangeConstructors(const char *name, Oid namespace,
NIL, /* parameterDefaults */
PointerGetDatum(NULL), /* trftypes */
PointerGetDatum(NULL), /* proconfig */
+ InvalidOid, /* prosupport */
1.0, /* procost */
0.0); /* prorows */
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8a3c2d..4c5f00d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -677,7 +677,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P
START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P
- SUBSCRIPTION SUBSTRING SYMMETRIC SYSID SYSTEM_P
+ SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P
TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN
TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM
@@ -7888,6 +7888,10 @@ common_func_opt_item:
{
$$ = makeDefElem("rows", (Node *)$2, @1);
}
+ | SUPPORT any_name
+ {
+ $$ = makeDefElem("support", (Node *)$2, @1);
+ }
| FunctionSetResetClause
{
/* we abuse the normal content of a DefElem here */
@@ -15218,6 +15222,7 @@ unreserved_keyword:
| STRICT_P
| STRIP_P
| SUBSCRIPTION
+ | SUPPORT
| SYSID
| SYSTEM_P
| TABLES
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 302df16..4bda11c 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2638,6 +2638,21 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
if (proc->prorows > 0 && proc->prorows != 1000)
appendStringInfo(&buf, " ROWS %g", proc->prorows);
+ if (proc->prosupport)
+ {
+ Oid argtypes[1];
+
+ /*
+ * We should qualify the support function's name if it wouldn't be
+ * resolved by lookup in the current search path.
+ */
+ argtypes[0] = INTERNALOID;
+ appendStringInfo(&buf, " SUPPORT %s",
+ generate_function_name(proc->prosupport, 1,
+ NIL, argtypes,
+ false, NULL, EXPR_KIND_NONE));
+ }
+
if (oldlen != buf.len)
appendStringInfoChar(&buf, '\n');
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2b1a947..615d997 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -11466,6 +11466,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
char *proconfig;
char *procost;
char *prorows;
+ char *prosupport;
char *proparallel;
char *lanname;
char *rettypename;
@@ -11488,7 +11489,26 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
asPart = createPQExpBuffer();
/* Fetch function-specific details */
- if (fout->remoteVersion >= 110000)
+ if (fout->remoteVersion >= 120000)
+ {
+ /*
+ * prosupport was added in 12
+ */
+ appendPQExpBuffer(query,
+ "SELECT proretset, prosrc, probin, "
+ "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
+ "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
+ "pg_catalog.pg_get_function_result(oid) AS funcresult, "
+ "array_to_string(protrftypes, ' ') AS protrftypes, "
+ "prokind, provolatile, proisstrict, prosecdef, "
+ "proleakproof, proconfig, procost, prorows, "
+ "prosupport, proparallel, "
+ "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
+ "FROM pg_catalog.pg_proc "
+ "WHERE oid = '%u'::pg_catalog.oid",
+ finfo->dobj.catId.oid);
+ }
+ else if (fout->remoteVersion >= 110000)
{
/*
* prokind was added in 11
@@ -11501,7 +11521,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"array_to_string(protrftypes, ' ') AS protrftypes, "
"prokind, provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
- "proparallel, "
+ "'-' AS prosupport, proparallel, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11521,7 +11541,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
- "proparallel, "
+ "'-' AS prosupport, proparallel, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11541,6 +11561,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
+ "'-' AS prosupport, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11559,6 +11580,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
"provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
+ "'-' AS prosupport, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11579,6 +11601,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
" proconfig, procost, prorows, "
+ "'-' AS prosupport, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11593,6 +11616,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"proconfig, procost, prorows, "
+ "'-' AS prosupport, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11607,6 +11631,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
+ "'-' AS prosupport, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11623,6 +11648,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
"provolatile, proisstrict, prosecdef, "
"false AS proleakproof, "
"null AS proconfig, 0 AS procost, 0 AS prorows, "
+ "'-' AS prosupport, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%u'::pg_catalog.oid",
@@ -11660,6 +11686,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
+ prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
if (PQfnumber(res, "proparallel") != -1)
proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
@@ -11873,6 +11900,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
appendPQExpBuffer(q, " ROWS %s", prorows);
+ if (strcmp(prosupport, "-") != 0)
+ {
+ /* We rely on regprocout to provide quoting and qualification */
+ appendPQExpBuffer(q, " SUPPORT %s", prosupport);
+ }
+
if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
{
if (proparallel[0] == PROPARALLEL_SAFE)
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 4ff358a..d22ca73 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -1774,6 +1774,20 @@ my %tests = (
unlike => { exclude_dump_test_schema => 1, },
},
+ 'CREATE FUNCTION ... SUPPORT' => {
+ create_order => 41,
+ create_sql =>
+ 'CREATE FUNCTION dump_test.func_with_support() RETURNS int LANGUAGE sql AS $$ SELECT 1 $$ SUPPORT varchar_support;',
+ regexp => qr/^
+ \QCREATE FUNCTION dump_test.func_with_support() RETURNS integer\E
+ \n\s+\QLANGUAGE sql SUPPORT varchar_support\E
+ \n\s+AS\ \$\$\Q SELECT 1 \E\$\$;
+ /xm,
+ like =>
+ { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+ unlike => { exclude_dump_test_schema => 1, },
+ },
+
'CREATE PROCEDURE dump_test.ptest1' => {
create_order => 41,
create_sql => 'CREATE PROCEDURE dump_test.ptest1(a int)
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b433769..e5270d2 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -201,6 +201,7 @@ extern ObjectAddress ProcedureCreate(const char *procedureName,
List *parameterDefaults,
Datum trftypes,
Datum proconfig,
+ Oid prosupport,
float4 procost,
float4 prorows);
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index adeb834..f054440 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -387,6 +387,7 @@ PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 7bb8ca9..4db792c 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3050,10 +3050,9 @@ DETAIL: System catalog modifications are currently disallowed.
-- instead create in public first, move to catalog
CREATE TABLE new_system_table(id serial primary key, othercol text);
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
--- XXX: it's currently impossible to move relations out of pg_catalog
ALTER TABLE new_system_table SET SCHEMA public;
-ERROR: cannot remove dependency on schema pg_catalog because it is a system object
--- move back, will be ignored -- already there
+ALTER TABLE new_system_table SET SCHEMA pg_catalog;
+-- will be ignored -- already there:
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
ALTER TABLE new_system_table RENAME TO old_system_table;
CREATE INDEX old_system_table__othercol ON old_system_table (othercol);
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index a498e4e..d806430 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -1896,10 +1896,9 @@ CREATE TABLE pg_catalog.new_system_table();
-- instead create in public first, move to catalog
CREATE TABLE new_system_table(id serial primary key, othercol text);
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
-
--- XXX: it's currently impossible to move relations out of pg_catalog
ALTER TABLE new_system_table SET SCHEMA public;
--- move back, will be ignored -- already there
+ALTER TABLE new_system_table SET SCHEMA pg_catalog;
+-- will be ignored -- already there:
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
ALTER TABLE new_system_table RENAME TO old_system_table;
CREATE INDEX old_system_table__othercol ON old_system_table (othercol);