Commit 12147499 authored by Tom Lane's avatar Tom Lane

Add support for multiple versions of an extension and ALTER EXTENSION UPDATE.

This follows recent discussions, so it's quite a bit different from
Dimitri's original.  There will probably be more changes once we get a bit
of experience with it, but let's get it in and start playing with it.

This is still just core code.  I'll start converting contrib modules
shortly.

Dimitri Fontaine and Tom Lane
parent 60141eef
......@@ -150,16 +150,11 @@ create_empty_extension(PG_FUNCTION_ARGS)
text *extName = PG_GETARG_TEXT_PP(0);
text *schemaName = PG_GETARG_TEXT_PP(1);
bool relocatable = PG_GETARG_BOOL(2);
char *extVersion;
text *extVersion = PG_GETARG_TEXT_PP(3);
Datum extConfig;
Datum extCondition;
List *requiredExtensions;
if (PG_ARGISNULL(3))
extVersion = NULL;
else
extVersion = text_to_cstring(PG_GETARG_TEXT_PP(3));
if (PG_ARGISNULL(4))
extConfig = PointerGetDatum(NULL);
else
......@@ -195,7 +190,7 @@ create_empty_extension(PG_FUNCTION_ARGS)
GetUserId(),
get_namespace_oid(text_to_cstring(schemaName), false),
relocatable,
extVersion,
text_to_cstring(extVersion),
extConfig,
extCondition,
requiredExtensions);
......
......@@ -2927,7 +2927,7 @@
<entry><structfield>extversion</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>Version string for the extension, or <literal>NULL</> if none</entry>
<entry>Version name for the extension</entry>
</row>
<row>
......
This diff is collapsed.
......@@ -23,6 +23,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> UPDATE [ TO <replaceable class="PARAMETER">new_version</replaceable> ]
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <replaceable class="PARAMETER">member_object</replaceable>
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP <replaceable class="PARAMETER">member_object</replaceable>
......@@ -61,6 +62,17 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP
extension. There are several subforms:
<variablelist>
<varlistentry>
<term><literal>UPDATE</literal></term>
<listitem>
<para>
This form updates the extension to a newer version. The extension
must supply a suitable update script (or series of scripts) that can
modify the currently-installed version into the requested version.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SET SCHEMA</literal></term>
<listitem>
......@@ -77,7 +89,7 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP
<listitem>
<para>
This form adds an existing object to the extension. This is mainly
useful in extension upgrade scripts. The object will subsequently
useful in extension update scripts. The object will subsequently
be treated as a member of the extension; notably, it can only be
dropped by dropping the extension.
</para>
......@@ -89,7 +101,7 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP
<listitem>
<para>
This form removes a member object from the extension. This is mainly
useful in extension upgrade scripts. The object is not dropped, only
useful in extension update scripts. The object is not dropped, only
disassociated from the extension.
</para>
</listitem>
......@@ -119,6 +131,18 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">new_version</replaceable></term>
<listitem>
<para>
The desired new version of the extension. This can be written as
either an identifier or a string literal. If not specified,
<command>ALTER EXTENSION UPDATE</> attempts to update to whatever is
shown as the default version in the extension's control file.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">new_schema</replaceable></term>
<listitem>
......@@ -231,7 +255,14 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP
<title>Examples</title>
<para>
To change the schema of the extension <literal>hstore</literal>
To update the <literal>hstore</literal> extension to version 2.0:
<programlisting>
ALTER EXTENSION hstore UPDATE TO '2.0';
</programlisting>
</para>
<para>
To change the schema of the <literal>hstore</literal> extension
to <literal>utils</literal>:
<programlisting>
ALTER EXTENSION hstore SET SCHEMA utils;
......
......@@ -22,7 +22,9 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
CREATE EXTENSION <replaceable class="parameter">extension_name</replaceable>
[ WITH ] [ SCHEMA [=] <replaceable class="parameter">schema</replaceable> ]
[ WITH ] [ SCHEMA <replaceable class="parameter">schema</replaceable> ]
[ VERSION <replaceable class="parameter">version</replaceable> ]
[ FROM <replaceable class="parameter">old_version</replaceable> ]
</synopsis>
</refsynopsisdiv>
......@@ -82,6 +84,44 @@ CREATE EXTENSION <replaceable class="parameter">extension_name</replaceable>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">version</replaceable></term>
<listitem>
<para>
The version of the extension to install. This can be written as
either an identifier or a string literal. The default version is
whatever is specified in the extension's control file.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">old_version</replaceable></term>
<listitem>
<para>
<literal>FROM</> <replaceable class="parameter">old_version</>
must be specified when, and only when, you are attempting to install
an extension that replaces an <quote>old style</> module that is just
a collection of objects not packaged into an extension. This option
causes <command>CREATE EXTENSION</> to run an alternative installation
script that absorbs the existing objects into the extension, instead
of creating new objects. Be careful that <literal>SCHEMA</> specifies
the schema containing these pre-existing objects.
</para>
<para>
The value to use for <replaceable
class="parameter">old_version</replaceable> is determined by the
extension's author, and might vary if there is more than one version
of the old-style module that can be upgraded into an extension.
For the standard additional modules supplied with pre-9.1
<productname>PostgreSQL</productname>, use <literal>unpackaged</>
for <replaceable class="parameter">old_version</replaceable> when
updating a module to extension style.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
......@@ -95,6 +135,16 @@ CREATE EXTENSION <replaceable class="parameter">extension_name</replaceable>
CREATE EXTENSION hstore;
</programlisting>
</para>
<para>
Update a pre-9.1 installation of <literal>hstore</> into
extension style:
<programlisting>
CREATE EXTENSION hstore SCHEMA public FROM unpackaged;
</programlisting>
Be careful to specify the schema in which you installed the existing
<literal>hstore</> objects.
</para>
</refsect1>
<refsect1>
......
This diff is collapsed.
......@@ -3251,6 +3251,17 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from)
return newnode;
}
static AlterExtensionStmt *
_copyAlterExtensionStmt(AlterExtensionStmt *from)
{
AlterExtensionStmt *newnode = makeNode(AlterExtensionStmt);
COPY_STRING_FIELD(extname);
COPY_NODE_FIELD(options);
return newnode;
}
static AlterExtensionContentsStmt *
_copyAlterExtensionContentsStmt(AlterExtensionContentsStmt *from)
{
......@@ -4267,6 +4278,9 @@ copyObject(void *from)
case T_CreateExtensionStmt:
retval = _copyCreateExtensionStmt(from);
break;
case T_AlterExtensionStmt:
retval = _copyAlterExtensionStmt(from);
break;
case T_AlterExtensionContentsStmt:
retval = _copyAlterExtensionContentsStmt(from);
break;
......
......@@ -1654,6 +1654,15 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
return true;
}
static bool
_equalAlterExtensionStmt(AlterExtensionStmt *a, AlterExtensionStmt *b)
{
COMPARE_STRING_FIELD(extname);
COMPARE_NODE_FIELD(options);
return true;
}
static bool
_equalAlterExtensionContentsStmt(AlterExtensionContentsStmt *a, AlterExtensionContentsStmt *b)
{
......@@ -2869,6 +2878,9 @@ equal(void *a, void *b)
case T_CreateExtensionStmt:
retval = _equalCreateExtensionStmt(a, b);
break;
case T_AlterExtensionStmt:
retval = _equalAlterExtensionStmt(a, b);
break;
case T_AlterExtensionContentsStmt:
retval = _equalAlterExtensionContentsStmt(a, b);
break;
......
......@@ -185,7 +185,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
AlterExtensionContentsStmt AlterForeignTableStmt
AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt
AlterDefaultPrivilegesStmt DefACLAction
......@@ -227,9 +227,11 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
%type <dbehavior> opt_drop_behavior
%type <list> createdb_opt_list alterdb_opt_list copy_opt_list
transaction_mode_list create_extension_opt_list
transaction_mode_list
create_extension_opt_list alter_extension_opt_list
%type <defelt> createdb_opt_item alterdb_opt_item copy_opt_item
transaction_mode_item create_extension_opt_item
transaction_mode_item
create_extension_opt_item alter_extension_opt_item
%type <ival> opt_lock lock_type cast_context
%type <ival> vacuum_option_list vacuum_option_elem
......@@ -664,6 +666,7 @@ stmt :
| AlterDefaultPrivilegesStmt
| AlterDomainStmt
| AlterEnumStmt
| AlterExtensionStmt
| AlterExtensionContentsStmt
| AlterFdwStmt
| AlterForeignServerStmt
......@@ -3222,7 +3225,7 @@ DropTableSpaceStmt: DROP TABLESPACE name
*
* QUERY:
* CREATE EXTENSION extension
* [ WITH ] [ SCHEMA [=] schema ]
* [ WITH ] [ SCHEMA schema ] [ VERSION version ] [ FROM oldversion ]
*
*****************************************************************************/
......@@ -3243,9 +3246,46 @@ create_extension_opt_list:
;
create_extension_opt_item:
SCHEMA opt_equal name
SCHEMA name
{
$$ = makeDefElem("schema", (Node *)makeString($2));
}
| VERSION_P ColId_or_Sconst
{
$$ = makeDefElem("new_version", (Node *)makeString($2));
}
| FROM ColId_or_Sconst
{
$$ = makeDefElem("old_version", (Node *)makeString($2));
}
;
/*****************************************************************************
*
* ALTER EXTENSION name UPDATE [ TO version ]
*
*****************************************************************************/
AlterExtensionStmt: ALTER EXTENSION name UPDATE alter_extension_opt_list
{
AlterExtensionStmt *n = makeNode(AlterExtensionStmt);
n->extname = $3;
n->options = $5;
$$ = (Node *) n;
}
;
alter_extension_opt_list:
alter_extension_opt_list alter_extension_opt_item
{ $$ = lappend($1, $2); }
| /* EMPTY */
{ $$ = NIL; }
;
alter_extension_opt_item:
TO ColId_or_Sconst
{
$$ = makeDefElem("schema", (Node *)makeString($3));
$$ = makeDefElem("new_version", (Node *)makeString($2));
}
;
......
......@@ -212,6 +212,7 @@ check_xact_readonly(Node *parsetree)
case T_AlterTSDictionaryStmt:
case T_AlterTSConfigurationStmt:
case T_CreateExtensionStmt:
case T_AlterExtensionStmt:
case T_AlterExtensionContentsStmt:
case T_CreateFdwStmt:
case T_AlterFdwStmt:
......@@ -601,6 +602,10 @@ standard_ProcessUtility(Node *parsetree,
CreateExtension((CreateExtensionStmt *) parsetree);
break;
case T_AlterExtensionStmt:
ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
break;
case T_AlterExtensionContentsStmt:
ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
break;
......@@ -1680,6 +1685,10 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE EXTENSION";
break;
case T_AlterExtensionStmt:
tag = "ALTER EXTENSION";
break;
case T_AlterExtensionContentsStmt:
tag = "ALTER EXTENSION";
break;
......@@ -2307,6 +2316,7 @@ GetCommandLogLevel(Node *parsetree)
break;
case T_CreateExtensionStmt:
case T_AlterExtensionStmt:
case T_AlterExtensionContentsStmt:
lev = LOGSTMT_DDL;
break;
......
......@@ -2725,9 +2725,6 @@ getExtensions(int *numExtensions)
extinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_extname));
extinfo[i].namespace = strdup(PQgetvalue(res, i, i_nspname));
extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
if (PQgetisnull(res, i, i_extversion))
extinfo[i].extversion = NULL;
else
extinfo[i].extversion = strdup(PQgetvalue(res, i, i_extversion));
extinfo[i].extconfig = strdup(PQgetvalue(res, i, i_extconfig));
extinfo[i].extcondition = strdup(PQgetvalue(res, i, i_extcondition));
......@@ -6942,10 +6939,7 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
appendStringLiteralAH(q, extinfo->namespace, fout);
appendPQExpBuffer(q, ", ");
appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
if (extinfo->extversion)
appendStringLiteralAH(q, extinfo->extversion, fout);
else
appendPQExpBuffer(q, "NULL");
appendPQExpBuffer(q, ", ");
/*
* Note that we're pushing extconfig (an OID array) back into
......
......@@ -868,7 +868,7 @@ psql_completion(char *text, int start, int end)
pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
{
static const char *const list_ALTEREXTENSION[] =
{"ADD", "DROP", "SET SCHEMA", NULL};
{"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(list_ALTEREXTENSION);
}
......
......@@ -36,9 +36,11 @@ CATALOG(pg_extension,3079)
bool extrelocatable; /* if true, allow ALTER EXTENSION SET SCHEMA */
/*
* VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
* VARIABLE LENGTH FIELDS start here.
*
* extversion should never be null, but the others can be.
*/
text extversion; /* extension version ID, if any */
text extversion; /* extension version name */
Oid extconfig[1]; /* dumpable configuration tables */
text extcondition[1]; /* WHERE clauses for config tables */
} FormData_pg_extension;
......
......@@ -37,6 +37,8 @@ extern Oid InsertExtensionTuple(const char *extName, Oid extOwner,
Datum extConfig, Datum extCondition,
List *requiredExtensions);
extern void ExecAlterExtensionStmt(AlterExtensionStmt *stmt);
extern void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt);
extern Oid get_extension_oid(const char *extname, bool missing_ok);
......
......@@ -356,6 +356,7 @@ typedef enum NodeTag
T_SecLabelStmt,
T_CreateForeignTableStmt,
T_CreateExtensionStmt,
T_AlterExtensionStmt,
T_AlterExtensionContentsStmt,
/*
......
......@@ -1546,6 +1546,14 @@ typedef struct CreateExtensionStmt
List *options; /* List of DefElem nodes */
} CreateExtensionStmt;
/* Only used for ALTER EXTENSION UPDATE; later might need an action field */
typedef struct AlterExtensionStmt
{
NodeTag type;
char *extname;
List *options; /* List of DefElem nodes */
} AlterExtensionStmt;
typedef struct AlterExtensionContentsStmt
{
NodeTag type;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment