mirror of
git://git.openembedded.org/meta-openembedded
synced 2026-01-01 13:58:06 +00:00
postgresql: Fix CVE-2022-2625
Upstream-Status: Backport from https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=5579726bd60a6e7afb04a3548bced348cd5ffd89 Description: CVE-2022-2625 postgresql: Extension scripts replace objects not belonging to the extension. Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
This commit is contained in:
parent
1e9bf08cca
commit
7952135f65
904
meta-oe/recipes-dbs/postgresql/files/CVE-2022-2625.patch
Normal file
904
meta-oe/recipes-dbs/postgresql/files/CVE-2022-2625.patch
Normal file
|
|
@ -0,0 +1,904 @@
|
|||
From 84375c1db25ef650902cf80712495fc514b0ff63 Mon Sep 17 00:00:00 2001
|
||||
From: Hitendra Prajapati <hprajapati@mvista.com>
|
||||
Date: Thu, 13 Oct 2022 10:35:32 +0530
|
||||
Subject: [PATCH] CVE-2022-2625
|
||||
|
||||
Upstream-Status: Backport [https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=5579726bd60a6e7afb04a3548bced348cd5ffd89]
|
||||
CVE: CVE-2022-2625
|
||||
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
|
||||
---
|
||||
doc/src/sgml/extend.sgml | 11 --
|
||||
src/backend/catalog/pg_collation.c | 49 ++++--
|
||||
src/backend/catalog/pg_depend.c | 74 ++++++++-
|
||||
src/backend/catalog/pg_operator.c | 2 +-
|
||||
src/backend/catalog/pg_type.c | 7 +-
|
||||
src/backend/commands/createas.c | 18 ++-
|
||||
src/backend/commands/foreigncmds.c | 19 ++-
|
||||
src/backend/commands/schemacmds.c | 25 ++-
|
||||
src/backend/commands/sequence.c | 8 +
|
||||
src/backend/commands/statscmds.c | 4 +
|
||||
src/backend/commands/view.c | 16 +-
|
||||
src/backend/parser/parse_utilcmd.c | 10 ++
|
||||
src/include/catalog/dependency.h | 2 +
|
||||
src/test/modules/test_extensions/Makefile | 5 +-
|
||||
.../expected/test_extensions.out | 153 ++++++++++++++++++
|
||||
.../test_extensions/sql/test_extensions.sql | 110 +++++++++++++
|
||||
.../test_ext_cine--1.0--1.1.sql | 26 +++
|
||||
.../test_extensions/test_ext_cine--1.0.sql | 25 +++
|
||||
.../test_extensions/test_ext_cine.control | 3 +
|
||||
.../test_extensions/test_ext_cor--1.0.sql | 20 +++
|
||||
.../test_extensions/test_ext_cor.control | 3 +
|
||||
21 files changed, 540 insertions(+), 50 deletions(-)
|
||||
create mode 100644 src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql
|
||||
create mode 100644 src/test/modules/test_extensions/test_ext_cine--1.0.sql
|
||||
create mode 100644 src/test/modules/test_extensions/test_ext_cine.control
|
||||
create mode 100644 src/test/modules/test_extensions/test_ext_cor--1.0.sql
|
||||
create mode 100644 src/test/modules/test_extensions/test_ext_cor.control
|
||||
|
||||
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
|
||||
index 53f2638..bcc7a80 100644
|
||||
--- a/doc/src/sgml/extend.sgml
|
||||
+++ b/doc/src/sgml/extend.sgml
|
||||
@@ -1109,17 +1109,6 @@ SELECT * FROM pg_extension_update_paths('<replaceable>extension_name</replaceabl
|
||||
<varname>search_path</varname>. However, no mechanism currently exists
|
||||
to require that.
|
||||
</para>
|
||||
-
|
||||
- <para>
|
||||
- Do <emphasis>not</emphasis> use <command>CREATE OR REPLACE
|
||||
- FUNCTION</command>, except in an update script that must change the
|
||||
- definition of a function that is known to be an extension member
|
||||
- already. (Likewise for other <literal>OR REPLACE</literal> options.)
|
||||
- Using <literal>OR REPLACE</literal> unnecessarily not only has a risk
|
||||
- of accidentally overwriting someone else's function, but it creates a
|
||||
- security hazard since the overwritten function would still be owned by
|
||||
- its original owner, who could modify it.
|
||||
- </para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
|
||||
index dd99d53..ba4c3ef 100644
|
||||
--- a/src/backend/catalog/pg_collation.c
|
||||
+++ b/src/backend/catalog/pg_collation.c
|
||||
@@ -78,15 +78,25 @@ CollationCreate(const char *collname, Oid collnamespace,
|
||||
* friendlier error message. The unique index provides a backstop against
|
||||
* race conditions.
|
||||
*/
|
||||
- if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||
- PointerGetDatum(collname),
|
||||
- Int32GetDatum(collencoding),
|
||||
- ObjectIdGetDatum(collnamespace)))
|
||||
+ oid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||
+ Anum_pg_collation_oid,
|
||||
+ PointerGetDatum(collname),
|
||||
+ Int32GetDatum(collencoding),
|
||||
+ ObjectIdGetDatum(collnamespace));
|
||||
+ if (OidIsValid(oid))
|
||||
{
|
||||
if (quiet)
|
||||
return InvalidOid;
|
||||
else if (if_not_exists)
|
||||
{
|
||||
+ /*
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddressSet(myself, CollationRelationId, oid);
|
||||
+ checkMembershipInCurrentExtension(&myself);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
collencoding == -1
|
||||
@@ -116,16 +126,19 @@ CollationCreate(const char *collname, Oid collnamespace,
|
||||
* so we take a ShareRowExclusiveLock earlier, to protect against
|
||||
* concurrent changes fooling this check.
|
||||
*/
|
||||
- if ((collencoding == -1 &&
|
||||
- SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||
- PointerGetDatum(collname),
|
||||
- Int32GetDatum(GetDatabaseEncoding()),
|
||||
- ObjectIdGetDatum(collnamespace))) ||
|
||||
- (collencoding != -1 &&
|
||||
- SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||
- PointerGetDatum(collname),
|
||||
- Int32GetDatum(-1),
|
||||
- ObjectIdGetDatum(collnamespace))))
|
||||
+ if (collencoding == -1)
|
||||
+ oid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||
+ Anum_pg_collation_oid,
|
||||
+ PointerGetDatum(collname),
|
||||
+ Int32GetDatum(GetDatabaseEncoding()),
|
||||
+ ObjectIdGetDatum(collnamespace));
|
||||
+ else
|
||||
+ oid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||
+ Anum_pg_collation_oid,
|
||||
+ PointerGetDatum(collname),
|
||||
+ Int32GetDatum(-1),
|
||||
+ ObjectIdGetDatum(collnamespace));
|
||||
+ if (OidIsValid(oid))
|
||||
{
|
||||
if (quiet)
|
||||
{
|
||||
@@ -134,6 +147,14 @@ CollationCreate(const char *collname, Oid collnamespace,
|
||||
}
|
||||
else if (if_not_exists)
|
||||
{
|
||||
+ /*
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddressSet(myself, CollationRelationId, oid);
|
||||
+ checkMembershipInCurrentExtension(&myself);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
table_close(rel, NoLock);
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
|
||||
index 9ffadbb..71c7cef 100644
|
||||
--- a/src/backend/catalog/pg_depend.c
|
||||
+++ b/src/backend/catalog/pg_depend.c
|
||||
@@ -124,15 +124,23 @@ recordMultipleDependencies(const ObjectAddress *depender,
|
||||
|
||||
/*
|
||||
* If we are executing a CREATE EXTENSION operation, mark the given object
|
||||
- * as being a member of the extension. Otherwise, do nothing.
|
||||
+ * as being a member of the extension, or check that it already is one.
|
||||
+ * Otherwise, do nothing.
|
||||
*
|
||||
* This must be called during creation of any user-definable object type
|
||||
* that could be a member of an extension.
|
||||
*
|
||||
- * If isReplace is true, the object already existed (or might have already
|
||||
- * existed), so we must check for a pre-existing extension membership entry.
|
||||
- * Passing false is a guarantee that the object is newly created, and so
|
||||
- * could not already be a member of any extension.
|
||||
+ * isReplace must be true if the object already existed, and false if it is
|
||||
+ * newly created. In the former case we insist that it already be a member
|
||||
+ * of the current extension. In the latter case we can skip checking whether
|
||||
+ * it is already a member of any extension.
|
||||
+ *
|
||||
+ * Note: isReplace = true is typically used when updating a object in
|
||||
+ * CREATE OR REPLACE and similar commands. We used to allow the target
|
||||
+ * object to not already be an extension member, instead silently absorbing
|
||||
+ * it into the current extension. However, this was both error-prone
|
||||
+ * (extensions might accidentally overwrite free-standing objects) and
|
||||
+ * a security hazard (since the object would retain its previous ownership).
|
||||
*/
|
||||
void
|
||||
recordDependencyOnCurrentExtension(const ObjectAddress *object,
|
||||
@@ -150,6 +158,12 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
|
||||
{
|
||||
Oid oldext;
|
||||
|
||||
+ /*
|
||||
+ * Side note: these catalog lookups are safe only because the
|
||||
+ * object is a pre-existing one. In the not-isReplace case, the
|
||||
+ * caller has most likely not yet done a CommandCounterIncrement
|
||||
+ * that would make the new object visible.
|
||||
+ */
|
||||
oldext = getExtensionOfObject(object->classId, object->objectId);
|
||||
if (OidIsValid(oldext))
|
||||
{
|
||||
@@ -163,6 +177,13 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
|
||||
getObjectDescription(object),
|
||||
get_extension_name(oldext))));
|
||||
}
|
||||
+ /* It's a free-standing object, so reject */
|
||||
+ ereport(ERROR,
|
||||
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
+ errmsg("%s is not a member of extension \"%s\"",
|
||||
+ getObjectDescription(object),
|
||||
+ get_extension_name(CurrentExtensionObject)),
|
||||
+ errdetail("An extension is not allowed to replace an object that it does not own.")));
|
||||
}
|
||||
|
||||
/* OK, record it as a member of CurrentExtensionObject */
|
||||
@@ -174,6 +195,49 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
|
||||
}
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * If we are executing a CREATE EXTENSION operation, check that the given
|
||||
+ * object is a member of the extension, and throw an error if it isn't.
|
||||
+ * Otherwise, do nothing.
|
||||
+ *
|
||||
+ * This must be called whenever a CREATE IF NOT EXISTS operation (for an
|
||||
+ * object type that can be an extension member) has found that an object of
|
||||
+ * the desired name already exists. It is insecure for an extension to use
|
||||
+ * IF NOT EXISTS except when the conflicting object is already an extension
|
||||
+ * member; otherwise a hostile user could substitute an object with arbitrary
|
||||
+ * properties.
|
||||
+ */
|
||||
+void
|
||||
+checkMembershipInCurrentExtension(const ObjectAddress *object)
|
||||
+{
|
||||
+ /*
|
||||
+ * This is actually the same condition tested in
|
||||
+ * recordDependencyOnCurrentExtension; but we want to issue a
|
||||
+ * differently-worded error, and anyway it would be pretty confusing to
|
||||
+ * call recordDependencyOnCurrentExtension in these circumstances.
|
||||
+ */
|
||||
+
|
||||
+ /* Only whole objects can be extension members */
|
||||
+ Assert(object->objectSubId == 0);
|
||||
+
|
||||
+ if (creating_extension)
|
||||
+ {
|
||||
+ Oid oldext;
|
||||
+
|
||||
+ oldext = getExtensionOfObject(object->classId, object->objectId);
|
||||
+ /* If already a member of this extension, OK */
|
||||
+ if (oldext == CurrentExtensionObject)
|
||||
+ return;
|
||||
+ /* Else complain */
|
||||
+ ereport(ERROR,
|
||||
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
+ errmsg("%s is not a member of extension \"%s\"",
|
||||
+ getObjectDescription(object),
|
||||
+ get_extension_name(CurrentExtensionObject)),
|
||||
+ errdetail("An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.")));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* deleteDependencyRecordsFor -- delete all records with given depender
|
||||
* classId/objectId. Returns the number of records deleted.
|
||||
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
|
||||
index bcaa26c..84784e6 100644
|
||||
--- a/src/backend/catalog/pg_operator.c
|
||||
+++ b/src/backend/catalog/pg_operator.c
|
||||
@@ -867,7 +867,7 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
|
||||
oper->oprowner);
|
||||
|
||||
/* Dependency on extension */
|
||||
- recordDependencyOnCurrentExtension(&myself, true);
|
||||
+ recordDependencyOnCurrentExtension(&myself, isUpdate);
|
||||
|
||||
return myself;
|
||||
}
|
||||
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
|
||||
index 2a51501..3ff017f 100644
|
||||
--- a/src/backend/catalog/pg_type.c
|
||||
+++ b/src/backend/catalog/pg_type.c
|
||||
@@ -528,10 +528,9 @@ TypeCreate(Oid newTypeOid,
|
||||
* If rebuild is true, we remove existing dependencies and rebuild them
|
||||
* from scratch. This is needed for ALTER TYPE, and also when replacing
|
||||
* a shell type. We don't remove an existing extension dependency, though.
|
||||
- * (That means an extension can't absorb a shell type created in another
|
||||
- * extension, nor ALTER a type created by another extension. Also, if it
|
||||
- * replaces a free-standing shell type or ALTERs a free-standing type,
|
||||
- * that type will become a member of the extension.)
|
||||
+ * That means an extension can't absorb a shell type that is free-standing
|
||||
+ * or belongs to another extension, nor ALTER a type that is free-standing or
|
||||
+ * belongs to another extension.
|
||||
*/
|
||||
void
|
||||
GenerateTypeDependencies(Oid typeObjectId,
|
||||
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
|
||||
index 4c1d909..a68d945 100644
|
||||
--- a/src/backend/commands/createas.c
|
||||
+++ b/src/backend/commands/createas.c
|
||||
@@ -243,15 +243,27 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
|
||||
if (stmt->if_not_exists)
|
||||
{
|
||||
Oid nspid;
|
||||
+ Oid oldrelid;
|
||||
|
||||
- nspid = RangeVarGetCreationNamespace(stmt->into->rel);
|
||||
+ nspid = RangeVarGetCreationNamespace(into->rel);
|
||||
|
||||
- if (get_relname_relid(stmt->into->rel->relname, nspid))
|
||||
+ oldrelid = get_relname_relid(into->rel->relname, nspid);
|
||||
+ if (OidIsValid(oldrelid))
|
||||
{
|
||||
+ /*
|
||||
+ * The relation exists and IF NOT EXISTS has been specified.
|
||||
+ *
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddressSet(address, RelationRelationId, oldrelid);
|
||||
+ checkMembershipInCurrentExtension(&address);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_TABLE),
|
||||
errmsg("relation \"%s\" already exists, skipping",
|
||||
- stmt->into->rel->relname)));
|
||||
+ into->rel->relname)));
|
||||
return InvalidObjectAddress;
|
||||
}
|
||||
}
|
||||
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
|
||||
index d7bc6e3..bc583c6 100644
|
||||
--- a/src/backend/commands/foreigncmds.c
|
||||
+++ b/src/backend/commands/foreigncmds.c
|
||||
@@ -887,13 +887,22 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
|
||||
ownerId = GetUserId();
|
||||
|
||||
/*
|
||||
- * Check that there is no other foreign server by this name. Do nothing if
|
||||
- * IF NOT EXISTS was enforced.
|
||||
+ * Check that there is no other foreign server by this name. If there is
|
||||
+ * one, do nothing if IF NOT EXISTS was specified.
|
||||
*/
|
||||
- if (GetForeignServerByName(stmt->servername, true) != NULL)
|
||||
+ srvId = get_foreign_server_oid(stmt->servername, true);
|
||||
+ if (OidIsValid(srvId))
|
||||
{
|
||||
if (stmt->if_not_exists)
|
||||
{
|
||||
+ /*
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddressSet(myself, ForeignServerRelationId, srvId);
|
||||
+ checkMembershipInCurrentExtension(&myself);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("server \"%s\" already exists, skipping",
|
||||
@@ -1182,6 +1191,10 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
|
||||
{
|
||||
if (stmt->if_not_exists)
|
||||
{
|
||||
+ /*
|
||||
+ * Since user mappings aren't members of extensions (see comments
|
||||
+ * below), no need for checkMembershipInCurrentExtension here.
|
||||
+ */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping",
|
||||
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
|
||||
index 6cf94a3..6bc4edc 100644
|
||||
--- a/src/backend/commands/schemacmds.c
|
||||
+++ b/src/backend/commands/schemacmds.c
|
||||
@@ -113,14 +113,25 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString,
|
||||
* the permissions checks, but since CREATE TABLE IF NOT EXISTS makes its
|
||||
* creation-permission check first, we do likewise.
|
||||
*/
|
||||
- if (stmt->if_not_exists &&
|
||||
- SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName)))
|
||||
+ if (stmt->if_not_exists)
|
||||
{
|
||||
- ereport(NOTICE,
|
||||
- (errcode(ERRCODE_DUPLICATE_SCHEMA),
|
||||
- errmsg("schema \"%s\" already exists, skipping",
|
||||
- schemaName)));
|
||||
- return InvalidOid;
|
||||
+ namespaceId = get_namespace_oid(schemaName, true);
|
||||
+ if (OidIsValid(namespaceId))
|
||||
+ {
|
||||
+ /*
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddressSet(address, NamespaceRelationId, namespaceId);
|
||||
+ checkMembershipInCurrentExtension(&address);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
+ ereport(NOTICE,
|
||||
+ (errcode(ERRCODE_DUPLICATE_SCHEMA),
|
||||
+ errmsg("schema \"%s\" already exists, skipping",
|
||||
+ schemaName)));
|
||||
+ return InvalidOid;
|
||||
+ }
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
|
||||
index 0960b33..0577184 100644
|
||||
--- a/src/backend/commands/sequence.c
|
||||
+++ b/src/backend/commands/sequence.c
|
||||
@@ -149,6 +149,14 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
|
||||
RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid);
|
||||
if (OidIsValid(seqoid))
|
||||
{
|
||||
+ /*
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddressSet(address, RelationRelationId, seqoid);
|
||||
+ checkMembershipInCurrentExtension(&address);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_TABLE),
|
||||
errmsg("relation \"%s\" already exists, skipping",
|
||||
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
|
||||
index 5678d31..409cf28 100644
|
||||
--- a/src/backend/commands/statscmds.c
|
||||
+++ b/src/backend/commands/statscmds.c
|
||||
@@ -173,6 +173,10 @@ CreateStatistics(CreateStatsStmt *stmt)
|
||||
{
|
||||
if (stmt->if_not_exists)
|
||||
{
|
||||
+ /*
|
||||
+ * Since stats objects aren't members of extensions (see comments
|
||||
+ * below), no need for checkMembershipInCurrentExtension here.
|
||||
+ */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("statistics object \"%s\" already exists, skipping",
|
||||
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
|
||||
index 87ed453..dd7cc97 100644
|
||||
--- a/src/backend/commands/view.c
|
||||
+++ b/src/backend/commands/view.c
|
||||
@@ -205,7 +205,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
- * Finally update the view options.
|
||||
+ * Update the view's options.
|
||||
*
|
||||
* The new options list replaces the existing options list, even if
|
||||
* it's empty.
|
||||
@@ -218,8 +218,22 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
|
||||
/* EventTriggerAlterTableStart called by ProcessUtilitySlow */
|
||||
AlterTableInternal(viewOid, atcmds, true);
|
||||
|
||||
+ /*
|
||||
+ * There is very little to do here to update the view's dependencies.
|
||||
+ * Most view-level dependency relationships, such as those on the
|
||||
+ * owner, schema, and associated composite type, aren't changing.
|
||||
+ * Because we don't allow changing type or collation of an existing
|
||||
+ * view column, those dependencies of the existing columns don't
|
||||
+ * change either, while the AT_AddColumnToView machinery took care of
|
||||
+ * adding such dependencies for new view columns. The dependencies of
|
||||
+ * the view's query could have changed arbitrarily, but that was dealt
|
||||
+ * with inside StoreViewQuery. What remains is only to check that
|
||||
+ * view replacement is allowed when we're creating an extension.
|
||||
+ */
|
||||
ObjectAddressSet(address, RelationRelationId, viewOid);
|
||||
|
||||
+ recordDependencyOnCurrentExtension(&address, true);
|
||||
+
|
||||
/*
|
||||
* Seems okay, so return the OID of the pre-existing view.
|
||||
*/
|
||||
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
|
||||
index 44aa38a..8f4d940 100644
|
||||
--- a/src/backend/parser/parse_utilcmd.c
|
||||
+++ b/src/backend/parser/parse_utilcmd.c
|
||||
@@ -206,6 +206,16 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
||||
*/
|
||||
if (stmt->if_not_exists && OidIsValid(existing_relid))
|
||||
{
|
||||
+ /*
|
||||
+ * If we are in an extension script, insist that the pre-existing
|
||||
+ * object be a member of the extension, to avoid security risks.
|
||||
+ */
|
||||
+ ObjectAddress address;
|
||||
+
|
||||
+ ObjectAddressSet(address, RelationRelationId, existing_relid);
|
||||
+ checkMembershipInCurrentExtension(&address);
|
||||
+
|
||||
+ /* OK to skip */
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_TABLE),
|
||||
errmsg("relation \"%s\" already exists, skipping",
|
||||
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
|
||||
index 8b1e3aa..27c7509 100644
|
||||
--- a/src/include/catalog/dependency.h
|
||||
+++ b/src/include/catalog/dependency.h
|
||||
@@ -201,6 +201,8 @@ extern void recordMultipleDependencies(const ObjectAddress *depender,
|
||||
extern void recordDependencyOnCurrentExtension(const ObjectAddress *object,
|
||||
bool isReplace);
|
||||
|
||||
+extern void checkMembershipInCurrentExtension(const ObjectAddress *object);
|
||||
+
|
||||
extern long deleteDependencyRecordsFor(Oid classId, Oid objectId,
|
||||
bool skipExtensionDeps);
|
||||
|
||||
diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile
|
||||
index d18108e..7428f15 100644
|
||||
--- a/src/test/modules/test_extensions/Makefile
|
||||
+++ b/src/test/modules/test_extensions/Makefile
|
||||
@@ -4,10 +4,13 @@ MODULE = test_extensions
|
||||
PGFILEDESC = "test_extensions - regression testing for EXTENSION support"
|
||||
|
||||
EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \
|
||||
- test_ext7 test_ext8 test_ext_cyclic1 test_ext_cyclic2
|
||||
+ test_ext7 test_ext8 test_ext_cine test_ext_cor \
|
||||
+ test_ext_cyclic1 test_ext_cyclic2
|
||||
DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \
|
||||
test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \
|
||||
test_ext7--1.0.sql test_ext7--1.0--2.0.sql test_ext8--1.0.sql \
|
||||
+ test_ext_cine--1.0.sql test_ext_cine--1.0--1.1.sql \
|
||||
+ test_ext_cor--1.0.sql \
|
||||
test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql
|
||||
|
||||
REGRESS = test_extensions test_extdepend
|
||||
diff --git a/src/test/modules/test_extensions/expected/test_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out
|
||||
index b5cbdfc..1e91640 100644
|
||||
--- a/src/test/modules/test_extensions/expected/test_extensions.out
|
||||
+++ b/src/test/modules/test_extensions/expected/test_extensions.out
|
||||
@@ -154,3 +154,156 @@ DROP TABLE test_ext4_tab;
|
||||
DROP FUNCTION create_extension_with_temp_schema();
|
||||
RESET client_min_messages;
|
||||
\unset SHOW_CONTEXT
|
||||
+-- It's generally bad style to use CREATE OR REPLACE unnecessarily.
|
||||
+-- Test what happens if an extension does it anyway.
|
||||
+-- Replacing a shell type or operator is sort of like CREATE OR REPLACE;
|
||||
+-- check that too.
|
||||
+CREATE FUNCTION ext_cor_func() RETURNS text
|
||||
+ AS $$ SELECT 'ext_cor_func: original'::text $$ LANGUAGE sql;
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+ERROR: function ext_cor_func() is not a member of extension "test_ext_cor"
|
||||
+DETAIL: An extension is not allowed to replace an object that it does not own.
|
||||
+SELECT ext_cor_func();
|
||||
+ ext_cor_func
|
||||
+------------------------
|
||||
+ ext_cor_func: original
|
||||
+(1 row)
|
||||
+
|
||||
+DROP FUNCTION ext_cor_func();
|
||||
+CREATE VIEW ext_cor_view AS
|
||||
+ SELECT 'ext_cor_view: original'::text AS col;
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+ERROR: view ext_cor_view is not a member of extension "test_ext_cor"
|
||||
+DETAIL: An extension is not allowed to replace an object that it does not own.
|
||||
+SELECT ext_cor_func();
|
||||
+ERROR: function ext_cor_func() does not exist
|
||||
+LINE 1: SELECT ext_cor_func();
|
||||
+ ^
|
||||
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
|
||||
+SELECT * FROM ext_cor_view;
|
||||
+ col
|
||||
+------------------------
|
||||
+ ext_cor_view: original
|
||||
+(1 row)
|
||||
+
|
||||
+DROP VIEW ext_cor_view;
|
||||
+CREATE TYPE test_ext_type;
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+ERROR: type test_ext_type is not a member of extension "test_ext_cor"
|
||||
+DETAIL: An extension is not allowed to replace an object that it does not own.
|
||||
+DROP TYPE test_ext_type;
|
||||
+-- this makes a shell "point <<@@ polygon" operator too
|
||||
+CREATE OPERATOR @@>> ( PROCEDURE = poly_contain_pt,
|
||||
+ LEFTARG = polygon, RIGHTARG = point,
|
||||
+ COMMUTATOR = <<@@ );
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+ERROR: operator <<@@(point,polygon) is not a member of extension "test_ext_cor"
|
||||
+DETAIL: An extension is not allowed to replace an object that it does not own.
|
||||
+DROP OPERATOR <<@@ (point, polygon);
|
||||
+CREATE EXTENSION test_ext_cor; -- now it should work
|
||||
+SELECT ext_cor_func();
|
||||
+ ext_cor_func
|
||||
+------------------------------
|
||||
+ ext_cor_func: from extension
|
||||
+(1 row)
|
||||
+
|
||||
+SELECT * FROM ext_cor_view;
|
||||
+ col
|
||||
+------------------------------
|
||||
+ ext_cor_view: from extension
|
||||
+(1 row)
|
||||
+
|
||||
+SELECT 'x'::test_ext_type;
|
||||
+ test_ext_type
|
||||
+---------------
|
||||
+ x
|
||||
+(1 row)
|
||||
+
|
||||
+SELECT point(0,0) <<@@ polygon(circle(point(0,0),1));
|
||||
+ ?column?
|
||||
+----------
|
||||
+ t
|
||||
+(1 row)
|
||||
+
|
||||
+\dx+ test_ext_cor
|
||||
+Objects in extension "test_ext_cor"
|
||||
+ Object description
|
||||
+------------------------------
|
||||
+ function ext_cor_func()
|
||||
+ operator <<@@(point,polygon)
|
||||
+ type test_ext_type
|
||||
+ view ext_cor_view
|
||||
+(4 rows)
|
||||
+
|
||||
+--
|
||||
+-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension
|
||||
+-- to be doing, but let's at least plug the major security hole in it.
|
||||
+--
|
||||
+CREATE COLLATION ext_cine_coll
|
||||
+ ( LC_COLLATE = "C", LC_CTYPE = "C" );
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: collation ext_cine_coll is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP COLLATION ext_cine_coll;
|
||||
+CREATE MATERIALIZED VIEW ext_cine_mv AS SELECT 11 AS f1;
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: materialized view ext_cine_mv is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP MATERIALIZED VIEW ext_cine_mv;
|
||||
+CREATE FOREIGN DATA WRAPPER dummy;
|
||||
+CREATE SERVER ext_cine_srv FOREIGN DATA WRAPPER dummy;
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: server ext_cine_srv is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP SERVER ext_cine_srv;
|
||||
+CREATE SCHEMA ext_cine_schema;
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: schema ext_cine_schema is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP SCHEMA ext_cine_schema;
|
||||
+CREATE SEQUENCE ext_cine_seq;
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: sequence ext_cine_seq is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP SEQUENCE ext_cine_seq;
|
||||
+CREATE TABLE ext_cine_tab1 (x int);
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: table ext_cine_tab1 is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP TABLE ext_cine_tab1;
|
||||
+CREATE TABLE ext_cine_tab2 AS SELECT 42 AS y;
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+ERROR: table ext_cine_tab2 is not a member of extension "test_ext_cine"
|
||||
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
|
||||
+DROP TABLE ext_cine_tab2;
|
||||
+CREATE EXTENSION test_ext_cine;
|
||||
+\dx+ test_ext_cine
|
||||
+Objects in extension "test_ext_cine"
|
||||
+ Object description
|
||||
+-----------------------------------
|
||||
+ collation ext_cine_coll
|
||||
+ foreign-data wrapper ext_cine_fdw
|
||||
+ materialized view ext_cine_mv
|
||||
+ schema ext_cine_schema
|
||||
+ sequence ext_cine_seq
|
||||
+ server ext_cine_srv
|
||||
+ table ext_cine_tab1
|
||||
+ table ext_cine_tab2
|
||||
+(8 rows)
|
||||
+
|
||||
+ALTER EXTENSION test_ext_cine UPDATE TO '1.1';
|
||||
+\dx+ test_ext_cine
|
||||
+Objects in extension "test_ext_cine"
|
||||
+ Object description
|
||||
+-----------------------------------
|
||||
+ collation ext_cine_coll
|
||||
+ foreign-data wrapper ext_cine_fdw
|
||||
+ materialized view ext_cine_mv
|
||||
+ schema ext_cine_schema
|
||||
+ sequence ext_cine_seq
|
||||
+ server ext_cine_srv
|
||||
+ table ext_cine_tab1
|
||||
+ table ext_cine_tab2
|
||||
+ table ext_cine_tab3
|
||||
+(9 rows)
|
||||
+
|
||||
diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql b/src/test/modules/test_extensions/sql/test_extensions.sql
|
||||
index f505466..b3d4579 100644
|
||||
--- a/src/test/modules/test_extensions/sql/test_extensions.sql
|
||||
+++ b/src/test/modules/test_extensions/sql/test_extensions.sql
|
||||
@@ -93,3 +93,113 @@ DROP TABLE test_ext4_tab;
|
||||
DROP FUNCTION create_extension_with_temp_schema();
|
||||
RESET client_min_messages;
|
||||
\unset SHOW_CONTEXT
|
||||
+
|
||||
+-- It's generally bad style to use CREATE OR REPLACE unnecessarily.
|
||||
+-- Test what happens if an extension does it anyway.
|
||||
+-- Replacing a shell type or operator is sort of like CREATE OR REPLACE;
|
||||
+-- check that too.
|
||||
+
|
||||
+CREATE FUNCTION ext_cor_func() RETURNS text
|
||||
+ AS $$ SELECT 'ext_cor_func: original'::text $$ LANGUAGE sql;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+
|
||||
+SELECT ext_cor_func();
|
||||
+
|
||||
+DROP FUNCTION ext_cor_func();
|
||||
+
|
||||
+CREATE VIEW ext_cor_view AS
|
||||
+ SELECT 'ext_cor_view: original'::text AS col;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+
|
||||
+SELECT ext_cor_func();
|
||||
+
|
||||
+SELECT * FROM ext_cor_view;
|
||||
+
|
||||
+DROP VIEW ext_cor_view;
|
||||
+
|
||||
+CREATE TYPE test_ext_type;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+
|
||||
+DROP TYPE test_ext_type;
|
||||
+
|
||||
+-- this makes a shell "point <<@@ polygon" operator too
|
||||
+CREATE OPERATOR @@>> ( PROCEDURE = poly_contain_pt,
|
||||
+ LEFTARG = polygon, RIGHTARG = point,
|
||||
+ COMMUTATOR = <<@@ );
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cor; -- fail
|
||||
+
|
||||
+DROP OPERATOR <<@@ (point, polygon);
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cor; -- now it should work
|
||||
+
|
||||
+SELECT ext_cor_func();
|
||||
+
|
||||
+SELECT * FROM ext_cor_view;
|
||||
+
|
||||
+SELECT 'x'::test_ext_type;
|
||||
+
|
||||
+SELECT point(0,0) <<@@ polygon(circle(point(0,0),1));
|
||||
+
|
||||
+\dx+ test_ext_cor
|
||||
+
|
||||
+--
|
||||
+-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension
|
||||
+-- to be doing, but let's at least plug the major security hole in it.
|
||||
+--
|
||||
+
|
||||
+CREATE COLLATION ext_cine_coll
|
||||
+ ( LC_COLLATE = "C", LC_CTYPE = "C" );
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP COLLATION ext_cine_coll;
|
||||
+
|
||||
+CREATE MATERIALIZED VIEW ext_cine_mv AS SELECT 11 AS f1;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP MATERIALIZED VIEW ext_cine_mv;
|
||||
+
|
||||
+CREATE FOREIGN DATA WRAPPER dummy;
|
||||
+
|
||||
+CREATE SERVER ext_cine_srv FOREIGN DATA WRAPPER dummy;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP SERVER ext_cine_srv;
|
||||
+
|
||||
+CREATE SCHEMA ext_cine_schema;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP SCHEMA ext_cine_schema;
|
||||
+
|
||||
+CREATE SEQUENCE ext_cine_seq;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP SEQUENCE ext_cine_seq;
|
||||
+
|
||||
+CREATE TABLE ext_cine_tab1 (x int);
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP TABLE ext_cine_tab1;
|
||||
+
|
||||
+CREATE TABLE ext_cine_tab2 AS SELECT 42 AS y;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine; -- fail
|
||||
+
|
||||
+DROP TABLE ext_cine_tab2;
|
||||
+
|
||||
+CREATE EXTENSION test_ext_cine;
|
||||
+
|
||||
+\dx+ test_ext_cine
|
||||
+
|
||||
+ALTER EXTENSION test_ext_cine UPDATE TO '1.1';
|
||||
+
|
||||
+\dx+ test_ext_cine
|
||||
diff --git a/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql b/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql
|
||||
new file mode 100644
|
||||
index 0000000..6dadfd2
|
||||
--- /dev/null
|
||||
+++ b/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql
|
||||
@@ -0,0 +1,26 @@
|
||||
+/* src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql */
|
||||
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
|
||||
+\echo Use "ALTER EXTENSION test_ext_cine UPDATE TO '1.1'" to load this file. \quit
|
||||
+
|
||||
+--
|
||||
+-- These are the same commands as in the 1.0 script; we expect them
|
||||
+-- to do nothing.
|
||||
+--
|
||||
+
|
||||
+CREATE COLLATION IF NOT EXISTS ext_cine_coll
|
||||
+ ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
|
||||
+
|
||||
+CREATE MATERIALIZED VIEW IF NOT EXISTS ext_cine_mv AS SELECT 42 AS f1;
|
||||
+
|
||||
+CREATE SERVER IF NOT EXISTS ext_cine_srv FOREIGN DATA WRAPPER ext_cine_fdw;
|
||||
+
|
||||
+CREATE SCHEMA IF NOT EXISTS ext_cine_schema;
|
||||
+
|
||||
+CREATE SEQUENCE IF NOT EXISTS ext_cine_seq;
|
||||
+
|
||||
+CREATE TABLE IF NOT EXISTS ext_cine_tab1 (x int);
|
||||
+
|
||||
+CREATE TABLE IF NOT EXISTS ext_cine_tab2 AS SELECT 42 AS y;
|
||||
+
|
||||
+-- just to verify the script ran
|
||||
+CREATE TABLE ext_cine_tab3 (z int);
|
||||
diff --git a/src/test/modules/test_extensions/test_ext_cine--1.0.sql b/src/test/modules/test_extensions/test_ext_cine--1.0.sql
|
||||
new file mode 100644
|
||||
index 0000000..01408ff
|
||||
--- /dev/null
|
||||
+++ b/src/test/modules/test_extensions/test_ext_cine--1.0.sql
|
||||
@@ -0,0 +1,25 @@
|
||||
+/* src/test/modules/test_extensions/test_ext_cine--1.0.sql */
|
||||
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
+\echo Use "CREATE EXTENSION test_ext_cine" to load this file. \quit
|
||||
+
|
||||
+--
|
||||
+-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension
|
||||
+-- to be doing, but let's at least plug the major security hole in it.
|
||||
+--
|
||||
+
|
||||
+CREATE COLLATION IF NOT EXISTS ext_cine_coll
|
||||
+ ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
|
||||
+
|
||||
+CREATE MATERIALIZED VIEW IF NOT EXISTS ext_cine_mv AS SELECT 42 AS f1;
|
||||
+
|
||||
+CREATE FOREIGN DATA WRAPPER ext_cine_fdw;
|
||||
+
|
||||
+CREATE SERVER IF NOT EXISTS ext_cine_srv FOREIGN DATA WRAPPER ext_cine_fdw;
|
||||
+
|
||||
+CREATE SCHEMA IF NOT EXISTS ext_cine_schema;
|
||||
+
|
||||
+CREATE SEQUENCE IF NOT EXISTS ext_cine_seq;
|
||||
+
|
||||
+CREATE TABLE IF NOT EXISTS ext_cine_tab1 (x int);
|
||||
+
|
||||
+CREATE TABLE IF NOT EXISTS ext_cine_tab2 AS SELECT 42 AS y;
|
||||
diff --git a/src/test/modules/test_extensions/test_ext_cine.control b/src/test/modules/test_extensions/test_ext_cine.control
|
||||
new file mode 100644
|
||||
index 0000000..ced713b
|
||||
--- /dev/null
|
||||
+++ b/src/test/modules/test_extensions/test_ext_cine.control
|
||||
@@ -0,0 +1,3 @@
|
||||
+comment = 'Test extension using CREATE IF NOT EXISTS'
|
||||
+default_version = '1.0'
|
||||
+relocatable = true
|
||||
diff --git a/src/test/modules/test_extensions/test_ext_cor--1.0.sql b/src/test/modules/test_extensions/test_ext_cor--1.0.sql
|
||||
new file mode 100644
|
||||
index 0000000..2e8d89c
|
||||
--- /dev/null
|
||||
+++ b/src/test/modules/test_extensions/test_ext_cor--1.0.sql
|
||||
@@ -0,0 +1,20 @@
|
||||
+/* src/test/modules/test_extensions/test_ext_cor--1.0.sql */
|
||||
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
+\echo Use "CREATE EXTENSION test_ext_cor" to load this file. \quit
|
||||
+
|
||||
+-- It's generally bad style to use CREATE OR REPLACE unnecessarily.
|
||||
+-- Test what happens if an extension does it anyway.
|
||||
+
|
||||
+CREATE OR REPLACE FUNCTION ext_cor_func() RETURNS text
|
||||
+ AS $$ SELECT 'ext_cor_func: from extension'::text $$ LANGUAGE sql;
|
||||
+
|
||||
+CREATE OR REPLACE VIEW ext_cor_view AS
|
||||
+ SELECT 'ext_cor_view: from extension'::text AS col;
|
||||
+
|
||||
+-- These are for testing replacement of a shell type/operator, which works
|
||||
+-- enough like an implicit OR REPLACE to be important to check.
|
||||
+
|
||||
+CREATE TYPE test_ext_type AS ENUM('x', 'y');
|
||||
+
|
||||
+CREATE OPERATOR <<@@ ( PROCEDURE = pt_contained_poly,
|
||||
+ LEFTARG = point, RIGHTARG = polygon );
|
||||
diff --git a/src/test/modules/test_extensions/test_ext_cor.control b/src/test/modules/test_extensions/test_ext_cor.control
|
||||
new file mode 100644
|
||||
index 0000000..0e972e5
|
||||
--- /dev/null
|
||||
+++ b/src/test/modules/test_extensions/test_ext_cor.control
|
||||
@@ -0,0 +1,3 @@
|
||||
+comment = 'Test extension using CREATE OR REPLACE'
|
||||
+default_version = '1.0'
|
||||
+relocatable = true
|
||||
--
|
||||
2.25.1
|
||||
|
||||
|
|
@ -8,6 +8,7 @@ SRC_URI += "\
|
|||
file://0001-Improve-reproducibility.patch \
|
||||
file://remove_duplicate.patch \
|
||||
file://CVE-2022-1552.patch \
|
||||
file://CVE-2022-2625.patch \
|
||||
"
|
||||
|
||||
SRC_URI[sha256sum] = "89fda2de33ed04a98548e43f3ee5f15b882be17505d631fe0dd1a540a2b56dce"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user