Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5bc178b

Browse files
committed
Implement "ALTER EXTENSION ADD object".
This is an essential component of making the extension feature usable; first because it's needed in the process of converting an existing installation containing "loose" objects of an old contrib module into the extension-based world, and second because we'll have to use it in pg_dump --binary-upgrade, as per recent discussion. Loosely based on part of Dimitri Fontaine's ALTER EXTENSION UPGRADE patch.
1 parent 70802e0 commit 5bc178b

File tree

10 files changed

+601
-255
lines changed

10 files changed

+601
-255
lines changed

doc/src/sgml/extend.sgml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,18 @@
331331
data; see below.)
332332
</para>
333333

334+
<para>
335+
The kinds of SQL objects that can be members of an extension are shown in
336+
the description of <xref linkend="sql-alterextension">. Notably, objects
337+
that are database-cluster-wide, such as databases, roles, and tablespaces,
338+
cannot be extension members since an extension is only known within one
339+
database. (Although an extension script is not prohibited from creating
340+
such objects, if it does so they will not be tracked as part of the
341+
extension.) Also notice that while a table can be a member of an
342+
extension, its subsidiary objects such as indexes are not directly
343+
considered members of the extension.
344+
</para>
345+
334346
<sect2>
335347
<title>Extension Files</title>
336348

doc/src/sgml/ref/alter_extension.sgml

Lines changed: 170 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,41 @@ PostgreSQL documentation
2323

2424
<refsynopsisdiv>
2525
<synopsis>
26-
ALTER EXTENSION <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
26+
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
27+
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <replaceable class="PARAMETER">member_object</replaceable>
28+
29+
<phrase>where <replaceable class="PARAMETER">member_object</replaceable> is:</phrase>
30+
31+
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable> [, ...] ) |
32+
CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>) |
33+
CONVERSION <replaceable class="PARAMETER">object_name</replaceable> |
34+
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
35+
FOREIGN DATA WRAPPER <replaceable class="PARAMETER">object_name</replaceable> |
36+
FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable> |
37+
FUNCTION <replaceable class="PARAMETER">function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) |
38+
OPERATOR <replaceable class="PARAMETER">operator_name</replaceable> (<replaceable class="PARAMETER">left_type</replaceable>, <replaceable class="PARAMETER">right_type</replaceable>) |
39+
OPERATOR CLASS <replaceable class="PARAMETER">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> |
40+
OPERATOR FAMILY <replaceable class="PARAMETER">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> |
41+
[ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">object_name</replaceable> |
42+
SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
43+
SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
44+
SERVER <replaceable class="PARAMETER">object_name</replaceable> |
45+
TABLE <replaceable class="PARAMETER">object_name</replaceable> |
46+
TEXT SEARCH CONFIGURATION <replaceable class="PARAMETER">object_name</replaceable> |
47+
TEXT SEARCH DICTIONARY <replaceable class="PARAMETER">object_name</replaceable> |
48+
TEXT SEARCH PARSER <replaceable class="PARAMETER">object_name</replaceable> |
49+
TEXT SEARCH TEMPLATE <replaceable class="PARAMETER">object_name</replaceable> |
50+
TYPE <replaceable class="PARAMETER">object_name</replaceable> |
51+
VIEW <replaceable class="PARAMETER">object_name</replaceable>
2752
</synopsis>
2853
</refsynopsisdiv>
2954

3055
<refsect1>
3156
<title>Description</title>
3257

3358
<para>
34-
<command>ALTER EXTENSION</command> changes the definition of an existing extension.
35-
Currently there is only one subform:
59+
<command>ALTER EXTENSION</command> changes the definition of an installed
60+
extension. There are several subforms:
3661

3762
<variablelist>
3863
<varlistentry>
@@ -41,37 +66,151 @@ ALTER EXTENSION <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <re
4166
<para>
4267
This form moves the extension's objects into another schema. The
4368
extension has to be <firstterm>relocatable</> for this command to
44-
succeed. See <xref linkend="extend-extensions"> for details.
69+
succeed.
70+
</para>
71+
</listitem>
72+
</varlistentry>
73+
74+
<varlistentry>
75+
<term><literal>ADD <replaceable class="PARAMETER">member_object</replaceable></literal></term>
76+
<listitem>
77+
<para>
78+
This form adds an existing object to the extension. This is mainly
79+
useful in extension upgrade scripts. The object will subsequently
80+
be treated as a member of the extension; notably, it can only be
81+
dropped by dropping the extension.
4582
</para>
4683
</listitem>
4784
</varlistentry>
4885
</variablelist>
86+
87+
See <xref linkend="extend-extensions"> for more information about these
88+
operations.
89+
</para>
90+
91+
<para>
92+
Only superusers can execute <command>ALTER EXTENSION</command>.
4993
</para>
5094
</refsect1>
5195

5296
<refsect1>
5397
<title>Parameters</title>
5498

55-
<para>
56-
<variablelist>
57-
<varlistentry>
58-
<term><replaceable class="PARAMETER">name</replaceable></term>
59-
<listitem>
60-
<para>
61-
The name of an installed extension.
62-
</para>
63-
</listitem>
64-
</varlistentry>
65-
66-
<varlistentry>
67-
<term><replaceable class="PARAMETER">new_schema</replaceable></term>
68-
<listitem>
69-
<para>
70-
The new schema for the extension.
71-
</para>
72-
</listitem>
73-
</varlistentry>
74-
</variablelist>
99+
<para>
100+
<variablelist>
101+
<varlistentry>
102+
<term><replaceable class="PARAMETER">extension_name</replaceable></term>
103+
<listitem>
104+
<para>
105+
The name of an installed extension.
106+
</para>
107+
</listitem>
108+
</varlistentry>
109+
110+
<varlistentry>
111+
<term><replaceable class="PARAMETER">new_schema</replaceable></term>
112+
<listitem>
113+
<para>
114+
The new schema for the extension.
115+
</para>
116+
</listitem>
117+
</varlistentry>
118+
119+
<varlistentry>
120+
<term><replaceable class="parameter">object_name</replaceable></term>
121+
<term><replaceable class="parameter">agg_name</replaceable></term>
122+
<term><replaceable class="parameter">function_name</replaceable></term>
123+
<term><replaceable class="parameter">operator_name</replaceable></term>
124+
<listitem>
125+
<para>
126+
The name of an object to be added to the extension. Names of tables,
127+
aggregates, domains, foreign tables, functions, operators,
128+
operator classes, operator families, sequences, text search objects,
129+
types, and views can be schema-qualified.
130+
</para>
131+
</listitem>
132+
</varlistentry>
133+
134+
<varlistentry>
135+
<term><replaceable class="parameter">agg_type</replaceable></term>
136+
<listitem>
137+
<para>
138+
An input data type on which the aggregate function operates.
139+
To reference a zero-argument aggregate function, write <literal>*</>
140+
in place of the list of input data types.
141+
</para>
142+
</listitem>
143+
</varlistentry>
144+
145+
<varlistentry>
146+
<term><replaceable>source_type</replaceable></term>
147+
<listitem>
148+
<para>
149+
The name of the source data type of the cast.
150+
</para>
151+
</listitem>
152+
</varlistentry>
153+
154+
<varlistentry>
155+
<term><replaceable>target_type</replaceable></term>
156+
<listitem>
157+
<para>
158+
The name of the target data type of the cast.
159+
</para>
160+
</listitem>
161+
</varlistentry>
162+
163+
<varlistentry>
164+
<term><replaceable class="parameter">argmode</replaceable></term>
165+
166+
<listitem>
167+
<para>
168+
The mode of a function argument: <literal>IN</>, <literal>OUT</>,
169+
<literal>INOUT</>, or <literal>VARIADIC</>.
170+
If omitted, the default is <literal>IN</>.
171+
Note that <command>ALTER EXTENSION</command> does not actually pay
172+
any attention to <literal>OUT</> arguments, since only the input
173+
arguments are needed to determine the function's identity.
174+
So it is sufficient to list the <literal>IN</>, <literal>INOUT</>,
175+
and <literal>VARIADIC</> arguments.
176+
</para>
177+
</listitem>
178+
</varlistentry>
179+
180+
<varlistentry>
181+
<term><replaceable class="parameter">argname</replaceable></term>
182+
183+
<listitem>
184+
<para>
185+
The name of a function argument.
186+
Note that <command>ALTER EXTENSION</command> does not actually pay
187+
any attention to argument names, since only the argument data
188+
types are needed to determine the function's identity.
189+
</para>
190+
</listitem>
191+
</varlistentry>
192+
193+
<varlistentry>
194+
<term><replaceable class="parameter">argtype</replaceable></term>
195+
196+
<listitem>
197+
<para>
198+
The data type(s) of the function's arguments (optionally
199+
schema-qualified), if any.
200+
</para>
201+
</listitem>
202+
</varlistentry>
203+
204+
<varlistentry>
205+
<term><literal>PROCEDURAL</literal></term>
206+
207+
<listitem>
208+
<para>
209+
This is a noise word.
210+
</para>
211+
</listitem>
212+
</varlistentry>
213+
</variablelist>
75214
</para>
76215
</refsect1>
77216

@@ -83,6 +222,13 @@ ALTER EXTENSION <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <re
83222
to <literal>utils</literal>:
84223
<programlisting>
85224
ALTER EXTENSION hstore SET SCHEMA utils;
225+
</programlisting>
226+
</para>
227+
228+
<para>
229+
To add an existing function to the <literal>hstore</literal> extension:
230+
<programlisting>
231+
ALTER EXTENSION hstore ADD FUNCTION populate_record(anyelement, hstore);
86232
</programlisting>
87233
</para>
88234
</refsect1>

src/backend/commands/extension.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
11341134
if (getExtensionOfObject(RelationRelationId, tableoid) !=
11351135
CurrentExtensionObject)
11361136
ereport(ERROR,
1137-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1137+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
11381138
errmsg("table \"%s\" is not a member of the extension being created",
11391139
tablename)));
11401140

@@ -1392,3 +1392,60 @@ AlterExtensionNamespace(List *names, const char *newschema)
13921392
changeDependencyFor(ExtensionRelationId, extensionOid,
13931393
NamespaceRelationId, oldNspOid, nspOid);
13941394
}
1395+
1396+
/*
1397+
* Execute ALTER EXTENSION ADD
1398+
*/
1399+
void
1400+
ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
1401+
{
1402+
ObjectAddress extension;
1403+
ObjectAddress object;
1404+
Relation relation;
1405+
1406+
/*
1407+
* For now, insist on superuser privilege. Later we might want to
1408+
* relax this to ownership of the target object and the extension.
1409+
*/
1410+
if (!superuser())
1411+
ereport(ERROR,
1412+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1413+
(errmsg("must be superuser to use ALTER EXTENSION"))));
1414+
1415+
/* Do this next to fail on nonexistent extension */
1416+
extension.classId = ExtensionRelationId;
1417+
extension.objectId = get_extension_oid(stmt->extname, false);
1418+
extension.objectSubId = 0;
1419+
1420+
/*
1421+
* Translate the parser representation that identifies the object into
1422+
* an ObjectAddress. get_object_address() will throw an error if the
1423+
* object does not exist, and will also acquire a lock on the object
1424+
* to guard against concurrent DROP and ALTER EXTENSION ADD operations.
1425+
*/
1426+
object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
1427+
&relation, ShareUpdateExclusiveLock);
1428+
1429+
/*
1430+
* Complain if object is already attached to some extension.
1431+
*/
1432+
if (getExtensionOfObject(object.classId, object.objectId) != InvalidOid)
1433+
ereport(ERROR,
1434+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1435+
errmsg("%s is already a member of an extension",
1436+
getObjectDescription(&object))));
1437+
1438+
/*
1439+
* OK, add the dependency.
1440+
*/
1441+
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
1442+
1443+
/*
1444+
* If get_object_address() opened the relation for us, we close it to keep
1445+
* the reference count correct - but we retain any locks acquired by
1446+
* get_object_address() until commit time, to guard against concurrent
1447+
* activity.
1448+
*/
1449+
if (relation != NULL)
1450+
relation_close(relation, NoLock);
1451+
}

src/backend/nodes/copyfuncs.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3250,6 +3250,19 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from)
32503250
return newnode;
32513251
}
32523252

3253+
static AlterExtensionAddStmt *
3254+
_copyAlterExtensionAddStmt(AlterExtensionAddStmt *from)
3255+
{
3256+
AlterExtensionAddStmt *newnode = makeNode(AlterExtensionAddStmt);
3257+
3258+
COPY_STRING_FIELD(extname);
3259+
COPY_SCALAR_FIELD(objtype);
3260+
COPY_NODE_FIELD(objname);
3261+
COPY_NODE_FIELD(objargs);
3262+
3263+
return newnode;
3264+
}
3265+
32533266
static CreateFdwStmt *
32543267
_copyCreateFdwStmt(CreateFdwStmt *from)
32553268
{
@@ -4252,6 +4265,9 @@ copyObject(void *from)
42524265
case T_CreateExtensionStmt:
42534266
retval = _copyCreateExtensionStmt(from);
42544267
break;
4268+
case T_AlterExtensionAddStmt:
4269+
retval = _copyAlterExtensionAddStmt(from);
4270+
break;
42554271
case T_CreateFdwStmt:
42564272
retval = _copyCreateFdwStmt(from);
42574273
break;

src/backend/nodes/equalfuncs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,6 +1654,17 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
16541654
return true;
16551655
}
16561656

1657+
static bool
1658+
_equalAlterExtensionAddStmt(AlterExtensionAddStmt *a, AlterExtensionAddStmt *b)
1659+
{
1660+
COMPARE_STRING_FIELD(extname);
1661+
COMPARE_SCALAR_FIELD(objtype);
1662+
COMPARE_NODE_FIELD(objname);
1663+
COMPARE_NODE_FIELD(objargs);
1664+
1665+
return true;
1666+
}
1667+
16571668
static bool
16581669
_equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b)
16591670
{
@@ -2857,6 +2868,9 @@ equal(void *a, void *b)
28572868
case T_CreateExtensionStmt:
28582869
retval = _equalCreateExtensionStmt(a, b);
28592870
break;
2871+
case T_AlterExtensionAddStmt:
2872+
retval = _equalAlterExtensionAddStmt(a, b);
2873+
break;
28602874
case T_CreateFdwStmt:
28612875
retval = _equalCreateFdwStmt(a, b);
28622876
break;

0 commit comments

Comments
 (0)