upgrade_extension.v0.patch
text/x-patch
Filename: upgrade_extension.v0.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v0
| File | + | − |
|---|---|---|
| contrib/citext/citext.control | 1 | 0 |
| contrib/citext/citext.upgrade.sql | 74 | 0 |
| contrib/citext/Makefile | 1 | 0 |
| contrib/lo/lo.control | 1 | 0 |
| contrib/lo/lo.upgrade.sql | 9 | 0 |
| contrib/lo/Makefile | 1 | 0 |
| contrib/pg_stat_statements/Makefile | 1 | 0 |
| contrib/pg_stat_statements/pg_stat_statements.control | 1 | 0 |
| contrib/pg_stat_statements/pg_stat_statements.upgrade.sql | 6 | 0 |
| contrib/unaccent/Makefile | 1 | 0 |
| contrib/unaccent/unaccent.control | 1 | 0 |
| contrib/unaccent/unaccent.upgrade.sql | 8 | 0 |
| src/backend/commands/alter.c | 69 | 0 |
| src/backend/commands/conversioncmds.c | 13 | 0 |
| src/backend/commands/extension.c | 460 | 0 |
| src/backend/commands/functioncmds.c | 24 | 0 |
| src/backend/commands/opclasscmds.c | 38 | 0 |
| src/backend/commands/operatorcmds.c | 20 | 0 |
| src/backend/commands/tablecmds.c | 17 | 0 |
| src/backend/commands/tsearchcmds.c | 40 | 0 |
| src/backend/commands/typecmds.c | 16 | 0 |
| src/backend/nodes/copyfuncs.c | 35 | 0 |
| src/backend/nodes/equalfuncs.c | 28 | 0 |
| src/backend/parser/gram.y | 172 | 0 |
| src/backend/tcop/utility.c | 76 | 0 |
| src/bin/pg_dump/pg_dump.c | 4 | 0 |
| src/bin/pg_dump/pg_dump.h | 1 | 0 |
| src/include/commands/alter.h | 1 | 0 |
| src/include/commands/conversioncmds.h | 1 | 0 |
| src/include/commands/defrem.h | 9 | 0 |
| src/include/commands/extension.h | 5 | 0 |
| src/include/commands/tablecmds.h | 2 | 0 |
| src/include/commands/typecmds.h | 1 | 0 |
| src/include/nodes/nodes.h | 2 | 0 |
| src/include/nodes/parsenodes.h | 22 | 0 |
| src/include/parser/kwlist.h | 1 | 0 |
*** a/contrib/citext/Makefile
--- b/contrib/citext/Makefile
***************
*** 1,6 ****
--- 1,7 ----
# contrib/citext/Makefile
MODULES = citext
+ DATA = citext.upgrade.sql
DATA_built = citext.sql
REGRESS = citext
*** a/contrib/citext/citext.control
--- b/contrib/citext/citext.control
***************
*** 2,4 ****
--- 2,5 ----
comment = 'case-insensitive character string type'
version = '9.1devel'
relocatable = true
+ upgrade_from_null = 'null => citext.upgrade.sql'
*** /dev/null
--- b/contrib/citext/citext.upgrade.sql
***************
*** 0 ****
--- 1,74 ----
+ /* contrib/citext/citext.upgrade.sql */
+
+ --
+ -- Upgrade the citext extension from before there was extension support
+ --
+
+ alter type @extschema@.citext set extension citext;
+ alter function @extschema@.citextin(cstring) set extension citext;
+ alter function @extschema@.citextout(@extschema@.citext) set extension citext;
+ alter function @extschema@.citextrecv(internal) set extension citext;
+ alter function @extschema@.citextsend(@extschema@.citext) set extension citext;
+ alter type @extschema@._citext set extension citext;
+ alter function @extschema@.citext(character) set extension citext;
+ alter function @extschema@.citext(boolean) set extension citext;
+ alter function @extschema@.citext(inet) set extension citext;
+ alter function @extschema@.citext_eq(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_ne(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_lt(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_le(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_gt(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_ge(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.=(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.<>(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.<(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.<=(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.>=(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.>(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_cmp(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_hash(@extschema@.citext) set extension citext;
+ alter operator family @extschema@.citext_ops using btree set extension citext;
+ alter operator class @extschema@.citext_ops using btree set extension citext;
+ alter operator family @extschema@.citext_ops using hash set extension citext;
+ alter operator class @extschema@.citext_ops using hash set extension citext;
+ alter function @extschema@.citext_smaller(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.citext_larger(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.min(@extschema@.citext) set extension citext;
+ alter function @extschema@.max(@extschema@.citext) set extension citext;
+ alter function @extschema@.texticlike(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.texticnlike(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.texticregexeq(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.texticregexne(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.~(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.~*(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.!~(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.!~*(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.~~(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.~~*(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.!~~(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter operator @extschema@.!~~*(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.texticlike(@extschema@.citext,text) set extension citext;
+ alter function @extschema@.texticnlike(@extschema@.citext,text) set extension citext;
+ alter function @extschema@.texticregexeq(@extschema@.citext,text) set extension citext;
+ alter function @extschema@.texticregexne(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.~(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.~*(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.!~(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.!~*(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.~~(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.~~*(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.!~~(@extschema@.citext,text) set extension citext;
+ alter operator @extschema@.!~~*(@extschema@.citext,text) set extension citext;
+ alter function @extschema@.regexp_matches(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.regexp_matches(@extschema@.citext,@extschema@.citext,text) set extension citext;
+ alter function @extschema@.regexp_replace(@extschema@.citext,@extschema@.citext,text) set extension citext;
+ alter function @extschema@.regexp_replace(@extschema@.citext,@extschema@.citext,text,text) set extension citext;
+ alter function @extschema@.regexp_split_to_array(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.regexp_split_to_array(@extschema@.citext,@extschema@.citext,text) set extension citext;
+ alter function @extschema@.regexp_split_to_table(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.regexp_split_to_table(@extschema@.citext,@extschema@.citext,text) set extension citext;
+ alter function @extschema@.strpos(@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.replace(@extschema@.citext,@extschema@.citext,@extschema@.citext) set extension citext;
+ alter function @extschema@.split_part(@extschema@.citext,@extschema@.citext,integer) set extension citext;
+ alter function @extschema@.translate(@extschema@.citext,@extschema@.citext,text) set extension citext;
+
*** a/contrib/lo/Makefile
--- b/contrib/lo/Makefile
***************
*** 1,6 ****
--- 1,7 ----
# contrib/lo/Makefile
MODULES = lo
+ DATA = lo.upgrade.sql
DATA_built = lo.sql
EXTENSION = $(MODULES)
*** a/contrib/lo/lo.control
--- b/contrib/lo/lo.control
***************
*** 2,4 ****
--- 2,5 ----
comment = 'managing Large Objects'
version = '9.1devel'
relocatable = true
+ upgrade_from_null = 'null => lo.upgrade.sql'
*** /dev/null
--- b/contrib/lo/lo.upgrade.sql
***************
*** 0 ****
--- 1,9 ----
+ /* contrib/lo/lo.upgrade.sql */
+
+ --
+ -- Upgrade the lo extension from before there was extension support
+ --
+
+ alter domain @extschema@.lo set extension lo;
+ alter function @extschema@.lo_oid(lo) set extension lo;
+ alter function @extschema@.lo_manage() set extension lo;
*** a/contrib/pg_stat_statements/Makefile
--- b/contrib/pg_stat_statements/Makefile
***************
*** 1,6 ****
--- 1,7 ----
# contrib/pg_stat_statements/Makefile
MODULE_big = pg_stat_statements
+ DATA = pg_stat_statements.upgrade.sql
DATA_built = pg_stat_statements.sql
OBJS = pg_stat_statements.o
*** a/contrib/pg_stat_statements/pg_stat_statements.control
--- b/contrib/pg_stat_statements/pg_stat_statements.control
***************
*** 2,4 ****
--- 2,5 ----
comment = 'tracking execution statistics of all SQL statements executed'
version = '9.1devel'
relocatable = true
+ upgrade_from_null = 'null => pg_stat_statements.upgrade.sql'
*** /dev/null
--- b/contrib/pg_stat_statements/pg_stat_statements.upgrade.sql
***************
*** 0 ****
--- 1,6 ----
+ /* contrib/pg_stat_statements/pg_stat_statements.upgrade.sql */
+
+ alter function @extschema@.pg_stat_statements_reset() set extension pg_stat_statements;
+ alter function @extschema@.pg_stat_statements() set extension pg_stat_statements;
+ alter view @extschema@.pg_stat_statements set extension pg_stat_statements;
+ alter type @extschema@.pg_stat_statements set extension pg_stat_statements;
*** a/contrib/unaccent/Makefile
--- b/contrib/unaccent/Makefile
***************
*** 3,8 ****
--- 3,9 ----
MODULE_big = unaccent
OBJS = unaccent.o
+ DATA = unaccent.upgrade.sql
DATA_built = unaccent.sql
DATA_TSEARCH = unaccent.rules
REGRESS = unaccent
*** a/contrib/unaccent/unaccent.control
--- b/contrib/unaccent/unaccent.control
***************
*** 2,4 ****
--- 2,5 ----
comment = 'text search dictionary that removes accents'
version = '9.1devel'
relocatable = true
+ upgrade_from_null = 'null => unaccent.upgrade.sql'
*** /dev/null
--- b/contrib/unaccent/unaccent.upgrade.sql
***************
*** 0 ****
--- 1,8 ----
+ /* contrib/unaccent/unaccent.upgrade.sql */
+
+ alter function @extschema@.unaccent(regdictionary,text) set extension unaccent;
+ alter function @extschema@.unaccent(text) set extension unaccent;
+ alter function @extschema@.unaccent_init(internal) set extension unaccent;
+ alter function @extschema@.unaccent_lexize(internal,internal,internal,internal) set extension unaccent;
+ alter text search template unaccent set extension unaccent;
+ alter text search dictionary unaccent set extension unaccent;
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 244,249 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 244,318 ----
}
/*
+ * Executes an ALTER OBJECT / SET EXTENSION statement. Based on the object
+ * type, the function appropriate to that type is executed.
+ */
+ void
+ ExecAlterObjectExtensionStmt(AlterObjectExtensionStmt *stmt)
+ {
+ switch (stmt->objectType)
+ {
+ case OBJECT_AGGREGATE:
+ AlterFunctionExtension(stmt->object, stmt->objarg, true,
+ stmt->extname);
+ break;
+
+ case OBJECT_CONVERSION:
+ AlterConversionExtension(stmt->object, stmt->extname);
+ break;
+
+ case OBJECT_FUNCTION:
+ AlterFunctionExtension(stmt->object, stmt->objarg, false,
+ stmt->extname);
+ break;
+
+ case OBJECT_OPERATOR:
+ AlterOperatorExtension(stmt->object, stmt->objarg, stmt->extname);
+ break;
+
+ case OBJECT_OPCLASS:
+ AlterOpClassExtension(stmt->object, stmt->objarg, stmt->extname);
+ break;
+
+ case OBJECT_OPFAMILY:
+ AlterOpFamilyExtension(stmt->object, stmt->objarg, stmt->extname);
+ break;
+
+ case OBJECT_SEQUENCE:
+ case OBJECT_TABLE:
+ case OBJECT_VIEW:
+ CheckRelationOwnership(stmt->relation, true);
+ AlterTableExtension(stmt->relation, stmt->extname);
+ break;
+
+ case OBJECT_TSPARSER:
+ AlterTSParserExtension(stmt->object, stmt->extname);
+ break;
+
+ case OBJECT_TSDICTIONARY:
+ AlterTSDictionaryExtension(stmt->object, stmt->extname);
+ break;
+
+ case OBJECT_TSTEMPLATE:
+ AlterTSTemplateExtension(stmt->object, stmt->extname);
+ break;
+
+ case OBJECT_TSCONFIGURATION:
+ AlterTSConfigurationExtension(stmt->object, stmt->extname);
+ break;
+
+ case OBJECT_TYPE:
+ case OBJECT_DOMAIN:
+ AlterTypeExtension(stmt->object, stmt->extname);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized AlterObjectExtensionStmt type: %d",
+ (int) stmt->objectType);
+ }
+ }
+
+ /*
* Generic function to change the namespace of a given object, for simple
* cases (won't work for tables or functions, objects which have more than 2
* key-attributes to use when searching for their syscache entries --- we
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 23,28 ****
--- 23,29 ----
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/conversioncmds.h"
+ #include "commands/extension.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
***************
*** 377,379 **** AlterConversionNamespace_oid(Oid convOid, Oid newNspOid)
--- 378,392 ----
heap_close(rel, NoLock);
return oldNspOid;
}
+
+ /*
+ * Execute ALTER CONVERSION SET EXTENSION
+ */
+ void
+ AlterConversionExtension(List *name, const char *extname)
+ {
+ Oid convOid;
+
+ convOid = get_conversion_oid(name, false);
+ AlterObjectExtension(extname, ConversionRelationId, convOid, 0);
+ }
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 55,60 ****
--- 55,61 ----
#include "utils/fmgroids.h"
#include "utils/genfile.h"
#include "utils/guc.h"
+ #include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
***************
*** 74,79 **** ObjectAddress CreateExtensionAddress;
--- 75,84 ----
bool create_extension = false;
bool create_extension_with_user_data = true;
+ static void
+ execute_extension_script(ExtensionControlFile *control,
+ const char *schema, bool create, bool user_data);
+
/*
* Utility functions to handle extension related paths
*/
***************
*** 168,182 **** get_extension_absolute_path(const char *filename)
* reading it is only allowed to superuser, so we don't even try to minimize
* memory allocation risks here.
*
! * Also note that only happens in CREATE EXTENSION and pg_extensions().
*
! * To support listing available extensions, the parameter init_gucs can be
! * set to false to inhibit any GUC processing.
*/
static ExtensionControlFile *
parse_extension_control_file(const char *extname,
const char *filename,
! bool init_gucs)
{
FILE *file;
bool saw_relocatable = false;
--- 173,190 ----
* reading it is only allowed to superuser, so we don't even try to minimize
* memory allocation risks here.
*
! * Also note that only happens in CREATE EXTENSION, ALTER EXTENSION UPGRADE
! * and pg_extensions() (used by psql \dx command).
*
! * When doing an upgrade we have to know from which version we're doing
! * it. This version can be NULL in case of upgrading from a "dummy"
! * extension.
*/
static ExtensionControlFile *
parse_extension_control_file(const char *extname,
const char *filename,
! bool upgrade,
! const char *version)
{
FILE *file;
bool saw_relocatable = false;
***************
*** 194,200 **** parse_extension_control_file(const char *extname,
* name, which ain't parsed
*/
control->name = pstrdup(extname);
! control->script = control->version = control->comment = NULL;
control->encoding = -1;
/*
--- 202,209 ----
* name, which ain't parsed
*/
control->name = pstrdup(extname);
! control->script =
! control->version = control->comment = control->upgrade = NULL;
control->encoding = -1;
/*
***************
*** 243,257 **** parse_extension_control_file(const char *extname,
errmsg("%s is not a valid encoding name in '%s'",
item->value, filename)));
}
else
ereport(ERROR,
(errmsg("Unsupported parameter '%s' in file: %s",
item->name, filename)));
}
! if (control->name == NULL)
ereport(ERROR,
! (errmsg("Missing a name parameter in file: %s", filename)));
/*
* Handle default values
--- 252,319 ----
errmsg("%s is not a valid encoding name in '%s'",
item->value, filename)));
}
+ /*
+ * upgrade settings are split in any number of variable, all
+ * beginning with "upgrade_from_" and with a value of the form:
+ *
+ * upgrade_from_null = 'null => lo.upgrade.sql'
+ * upgrade_from_9_1 = '9.1.* => lo.upgrade.1.sql'
+ *
+ * We simply ignore the parameters when upgrade is false.
+ *
+ * strlen("upgrade_from_") = 13
+ */
+ else if (strncmp(item->name, "upgrade_from_", 13) == 0)
+ {
+ /* first match win */
+ if (upgrade && control->upgrade == NULL)
+ {
+ char *sep = "=>";
+ char *re = text_to_cstring(
+ DatumGetTextPP(
+ DirectFunctionCall1(
+ btrim1,
+ DirectFunctionCall3(
+ split_text,
+ PointerGetDatum(cstring_to_text(item->value)),
+ PointerGetDatum(cstring_to_text(sep)), 1))));
+
+ char *filename = text_to_cstring(
+ DatumGetTextPP(
+ DirectFunctionCall1(
+ btrim1,
+ DirectFunctionCall3(
+ split_text,
+ PointerGetDatum(cstring_to_text(item->value)),
+ PointerGetDatum(cstring_to_text(sep)), 2))));
+
+ /* re is "null" to match current version being null */
+ if (version == NULL)
+ {
+ if (strcmp(re, "null") == 0)
+ control->upgrade = pstrdup(filename);
+ }
+ /* regexp match: re ~ version */
+ else if (DatumGetBool(
+ DirectFunctionCall2(
+ textregexeq,
+ PointerGetDatum(cstring_to_text(version)),
+ PointerGetDatum(cstring_to_text(re)))))
+ {
+ control->upgrade = pstrdup(filename);
+ }
+ }
+ }
else
ereport(ERROR,
(errmsg("Unsupported parameter '%s' in file: %s",
item->name, filename)));
}
! if (upgrade && control->upgrade == NULL)
ereport(ERROR,
! (errmsg("No matching regexp to upgrade extension \"%s\" from version \"%s\"",
! control->name, version)));
/*
* Handle default values
***************
*** 282,294 **** parse_extension_control_file(const char *extname,
* We're given an extension name, parse the {extname}.control file.
*/
static ExtensionControlFile *
! read_extension_control_file(const char *extname, bool init_gucs)
{
char *filename = get_extension_control_filename(extname);
if (access(filename, R_OK) == 0)
{
! return parse_extension_control_file(extname, filename, true);
}
ereport(ERROR,
--- 344,358 ----
* We're given an extension name, parse the {extname}.control file.
*/
static ExtensionControlFile *
! read_extension_control_file(const char *extname,
! bool upgrade, const char *version)
{
char *filename = get_extension_control_filename(extname);
if (access(filename, R_OK) == 0)
{
! return parse_extension_control_file(extname, filename,
! upgrade, version);
}
ereport(ERROR,
***************
*** 303,312 **** read_extension_control_file(const char *extname, bool init_gucs)
* Read the SQL script into a string, and care for its encoding
*/
static char *
! read_extension_script_file(const ExtensionControlFile *control,
! const char *encoding_name)
{
! char *filename = get_extension_absolute_path(control->script);
Datum script = CStringGetTextDatum(filename);
Datum raw = DirectFunctionCall1(pg_read_binary_file_all, script);
int src_encoding;
--- 367,376 ----
* Read the SQL script into a string, and care for its encoding
*/
static char *
! read_extension_script_file(const ExtensionControlFile *control, bool create)
{
! char *scriptname = create ? control->script : control->upgrade;
! char *filename = get_extension_absolute_path(scriptname);
Datum script = CStringGetTextDatum(filename);
Datum raw = DirectFunctionCall1(pg_read_binary_file_all, script);
int src_encoding;
***************
*** 317,332 **** read_extension_script_file(const ExtensionControlFile *control,
int len;
/* use database encoding if not given */
! if (encoding_name == NULL)
src_encoding = dest_encoding;
else
! src_encoding = pg_char_to_encoding(encoding_name);
if (src_encoding < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid source encoding name \"%s\"",
! encoding_name)));
content = (bytea *)DatumGetPointer(raw);
--- 381,396 ----
int len;
/* use database encoding if not given */
! if (control->encoding == -1)
src_encoding = dest_encoding;
else
! src_encoding = control->encoding;
if (src_encoding < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid source encoding name \"%s\"",
! pg_encoding_to_char(control->encoding))));
content = (bytea *)DatumGetPointer(raw);
***************
*** 372,377 **** execute_sql_string(const char *sql)
--- 436,586 ----
}
/*
+ * Execute given script to install or upgrade an extension
+ *
+ * Caller must have prepared CreateExtensionAddress.
+ */
+ static void
+ execute_extension_script(ExtensionControlFile *control,
+ const char *schema, bool create, bool user_data)
+ {
+ char *script = create ? control->script : control->upgrade;
+ char *filename = get_extension_absolute_path(script);
+ char *old_cmsgs = NULL, *old_lmsgs = NULL; /* silence compiler */
+ bool reset_cmsgs = false, reset_lmsgs = false;
+
+ /*
+ * Set create_extension and create_extension_with_user_data so that the
+ * function pg_extension_with_user_data() returns the right value.
+ */
+ create_extension = true;
+ create_extension_with_user_data = user_data;
+
+ elog(DEBUG1,
+ "%s extension '%s' from '%s', in schema %s, %s user data",
+ create ? "Installing" : "Upgrading",
+ control->name,
+ filename,
+ schema ? schema : "public",
+ create_extension_with_user_data ? "with" : "without");
+
+ /*
+ * Force the min message settings here, because SPI will dump the
+ * query_string into the messages and in this case, that's a full
+ * extension script. At the time of this writing, contrib/isn/isn.sql.in
+ * is already 3197 lines and will issue lots of CREATE TYPE shell
+ * notices.
+ *
+ * We want to avoid dumping the full script for each of those.
+ */
+ reset_cmsgs = client_min_messages < WARNING;
+ reset_lmsgs = log_min_messages < WARNING;
+
+ if (reset_cmsgs)
+ {
+ old_cmsgs = pstrdup((char *)GetConfigOption("client_min_messages", false));
+ SetConfigOption("client_min_messages", "warning", PGC_SUSET, PGC_S_SESSION);
+ }
+ if (reset_lmsgs)
+ {
+ old_lmsgs = pstrdup((char *)GetConfigOption("log_min_messages", false));
+ SetConfigOption("log_min_messages", "warning", PGC_SUSET, PGC_S_SESSION);
+ }
+
+ /*
+ * On failure, ensure that create_extension does not remain set.
+ */
+ PG_TRY();
+ {
+ char *sql = read_extension_script_file(control, create);
+
+ elog(DEBUG1, "Execute script \"%s\"", filename);
+
+ /*
+ * An extension that is relocatable does not need any replacement,
+ * we will ALTER EXTENSION SET SCHEMA just after installing it. See
+ * below for details.
+ *
+ * An extension that is not relocatable need to offer a mechanism
+ * for the users to be able to choose where to intall it, that's
+ * using the placeholder @extschema@.
+ *
+ * At upgrade time, it's highly possible that the script will need
+ * to ALTER already existing objects, so we only offer support for
+ * the placeholder @extschema@.
+ */
+ if (create && control->relocatable)
+ {
+ List *search_path = fetch_search_path(false);
+ Oid first_schema, target_schema;
+
+ if (!execute_sql_string(sql))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("could not execute sql file: '%s'", filename)));
+
+ /*
+ * CREATE EXTENSION foo WITH SCHEMA bar;
+ *
+ * The extension is relocatable, so we run its install script
+ * and it has to install all objects into the same schema. Then
+ * we relocate all the objects to the target SCHEMA bar,
+ * ERRORing out if some objects are not in the same schema than
+ * others, that's doing:
+ *
+ * ALTER EXTENSION foo SET SCHEMA bar;
+ *
+ * We skip this step if the target schema happens to be the
+ * first schema of the current search_path.
+ */
+ first_schema = linitial_oid(search_path);
+ target_schema = LookupCreationNamespace(schema);
+ list_free(search_path);
+
+ if (first_schema != target_schema)
+ AlterExtensionNamespace_oid(CreateExtensionAddress.objectId,
+ target_schema);
+ }
+ else
+ {
+ /*
+ * Prepare the replacements we use in execute_sql_file(). Even if
+ * the schema has not been specified by the user, we still have to
+ * set @extschema@ to 'public' so that extension scripts can rely on
+ * this placeholder.
+ */
+ sql = text_to_cstring(
+ DatumGetTextPP(
+ DirectFunctionCall3(replace_text,
+ CStringGetTextDatum(sql),
+ CStringGetTextDatum("@extschema@"),
+ CStringGetTextDatum(schema))));
+
+ if (!execute_sql_string(sql))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATA_EXCEPTION),
+ errmsg("could not execute sql file: '%s'", filename)));
+ }
+ }
+ PG_CATCH();
+ {
+ create_extension = false;
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+
+ if (reset_cmsgs)
+ SetConfigOption("client_min_messages",
+ old_cmsgs, PGC_SUSET, PGC_S_SESSION);
+ if (reset_lmsgs)
+ SetConfigOption("log_min_messages",
+ old_lmsgs, PGC_SUSET, PGC_S_SESSION);
+
+ /* reset the current_extension dependency tracker */
+ create_extension = false;
+ }
+
+ /*
* CREATE EXTENSION
*
* Only superusers can create an extension.
***************
*** 379,391 **** execute_sql_string(const char *sql)
void
CreateExtension(CreateExtensionStmt *stmt)
{
-
ListCell *option;
DefElem *d_user_data = NULL;
DefElem *d_schema = NULL;
bool user_data = true;
char *schema = NULL;
- int encoding = -1;
ExtensionControlFile *control;
--- 588,599 ----
void
CreateExtension(CreateExtensionStmt *stmt)
{
ListCell *option;
DefElem *d_user_data = NULL;
DefElem *d_schema = NULL;
+ DefElem *d_sysid = NULL;
bool user_data = true;
char *schema = NULL;
ExtensionControlFile *control;
***************
*** 393,402 **** CreateExtension(CreateExtensionStmt *stmt)
Datum values[Natts_pg_extension];
bool nulls[Natts_pg_extension];
HeapTuple tuple;
! Oid extensionoid;
!
! char *old_cmsgs = NULL, *old_lmsgs = NULL; /* silence compiler */
! bool reset_cmsgs = false, reset_lmsgs = false;
/* Must be super user */
if (!superuser())
--- 601,607 ----
Datum values[Natts_pg_extension];
bool nulls[Natts_pg_extension];
HeapTuple tuple;
! Oid extensionoid = InvalidOid;
/* Must be super user */
if (!superuser())
***************
*** 426,432 **** CreateExtension(CreateExtensionStmt *stmt)
* apply to reading the script, so we have to read it before to know
* which encoding to choose.
*/
! control = read_extension_control_file(stmt->extname, true);
/*
* Read the statement option list
--- 631,637 ----
* apply to reading the script, so we have to read it before to know
* which encoding to choose.
*/
! control = read_extension_control_file(stmt->extname, false, NULL);
/*
* Read the statement option list
***************
*** 438,444 **** CreateExtension(CreateExtensionStmt *stmt)
if (strcmp(defel->defname, "user_data") == 0)
{
! if (d_user_data)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
--- 643,649 ----
if (strcmp(defel->defname, "user_data") == 0)
{
! if (d_user_data || d_sysid)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
***************
*** 452,457 **** CreateExtension(CreateExtensionStmt *stmt)
--- 657,670 ----
errmsg("conflicting or redundant options")));
d_schema = defel;
}
+ else if (strcmp(defel->defname, "sysid") == 0)
+ {
+ if (d_sysid || d_user_data)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ d_sysid = defel;
+ }
}
if (d_user_data && d_user_data->arg)
***************
*** 466,486 **** CreateExtension(CreateExtensionStmt *stmt)
*/
schema = pstrdup("public");
! if (control->encoding != -1)
! {
! /* The encoding has already been validated */
! encoding = control->encoding;
! }
! else
{
! /* default to utf8 encoding */
! encoding = PG_UTF8;
}
elog(DEBUG1, "CreateExtensionStmt: %s user data, schema = '%s', encoding = '%s'",
user_data ? "with" : "without",
schema,
! pg_encoding_to_char(encoding));
/*
* Insert tuple into pg_extension.
--- 679,701 ----
*/
schema = pstrdup("public");
! if (d_sysid && d_sysid->arg)
{
! extensionoid = (Oid) intVal(d_sysid->arg);
! if (extensionoid <= InvalidOid || extensionoid > OID_MAX)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! errmsg("invalid Oid: %d", extensionoid)));
}
+ /* default to utf8 encoding */
+ if (control->encoding == -1)
+ control->encoding = PG_UTF8;
+
elog(DEBUG1, "CreateExtensionStmt: %s user data, schema = '%s', encoding = '%s'",
user_data ? "with" : "without",
schema,
! pg_encoding_to_char(control->encoding));
/*
* Insert tuple into pg_extension.
***************
*** 504,509 **** CreateExtension(CreateExtensionStmt *stmt)
--- 719,737 ----
errmsg("extension \"%s\" already exists", stmt->extname)));
}
+ if (OidIsValid(extensionoid))
+ {
+ char *extname = get_extension_name(extensionoid);
+ elog(DEBUG1, "checking for extension with OID %u: %s", extensionoid, extname);
+
+ if( extname != NULL )
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("extension \"%s\" already exists", extname)));
+ }
+ }
+
memset(values, 0, sizeof(values));
MemSet(nulls, false, sizeof(nulls));
***************
*** 513,526 **** CreateExtension(CreateExtensionStmt *stmt)
values[Anum_pg_extension_relocatable - 1] =
BoolGetDatum(control->relocatable);
! if( control->version == NULL )
nulls[Anum_pg_extension_extversion - 1] = true;
else
values[Anum_pg_extension_extversion - 1] =
CStringGetTextDatum(control->version);
! tuple = heap_form_tuple(rel->rd_att, values, nulls);
extensionoid = simple_heap_insert(rel, tuple);
CatalogUpdateIndexes(rel, tuple);
heap_freetuple(tuple);
heap_close(rel, ExclusiveLock);
--- 741,766 ----
values[Anum_pg_extension_relocatable - 1] =
BoolGetDatum(control->relocatable);
! /*
! * We force version to NULL when CREATE WRAPPER EXTENSION is used: then
! * we UPGRADE from NULL */
! if( control->version == NULL || stmt->wrapper)
nulls[Anum_pg_extension_extversion - 1] = true;
else
values[Anum_pg_extension_extversion - 1] =
CStringGetTextDatum(control->version);
! tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
!
! /*
! * CREATE EXTENSION WITH OIDS allows to force it for upgrading
! */
! if (OidIsValid(extensionoid))
! HeapTupleSetOid(tuple, extensionoid);
extensionoid = simple_heap_insert(rel, tuple);
+
+ elog(DEBUG1, "HeapTupleIsValid: %s", HeapTupleIsValid(tuple) ? "true" : "false");
+
CatalogUpdateIndexes(rel, tuple);
heap_freetuple(tuple);
heap_close(rel, ExclusiveLock);
***************
*** 539,658 **** CreateExtension(CreateExtensionStmt *stmt)
CreateExtensionAddress.classId = ExtensionRelationId;
CreateExtensionAddress.objectId = extensionoid;
CreateExtensionAddress.objectSubId = 0;
- create_extension = true;
-
- /*
- * Also set create_extension_with_user_data so that the function
- * pg_extension_with_user_data returns the right value.
- */
- create_extension_with_user_data = user_data;
-
- elog(DEBUG1,
- "Installing extension '%s' from '%s', in schema %s, %s user data",
- stmt->extname,
- get_extension_absolute_path(control->script),
- schema ? schema : "public",
- create_extension_with_user_data ? "with" : "without");
-
- /*
- * Force the min message settings here, because SPI will dump the
- * query_string into the messages and in this case, that's a full
- * extension script. At the time of this writing, contrib/isn/isn.sql.in
- * is already 3197 lines and will issue lots of CREATE TYPE shell
- * notices.
- *
- * We want to avoid dumping the full script for each of those.
- */
- reset_cmsgs = client_min_messages < WARNING;
- reset_lmsgs = log_min_messages < WARNING;
-
- if (reset_cmsgs)
- {
- old_cmsgs = pstrdup((char *)GetConfigOption("client_min_messages", false));
- SetConfigOption("client_min_messages", "warning", PGC_SUSET, PGC_S_SESSION);
- }
- if (reset_lmsgs)
- {
- old_lmsgs = pstrdup((char *)GetConfigOption("log_min_messages", false));
- SetConfigOption("log_min_messages", "warning", PGC_SUSET, PGC_S_SESSION);
- }
-
- /*
- * On failure, ensure that create_extension does not remain set.
- */
- PG_TRY();
- {
- char *filename = get_extension_absolute_path(control->script);
- char *sql = read_extension_script_file(control,
- pg_encoding_to_char(encoding));
-
- /*
- * An extension that is relocatable does not need any replacement,
- * we will ALTER EXTENSION SET SCHEMA just after installing it. See
- * below for details.
- *
- * An extension that is not relocatable need to offer a mechanism
- * for the users to be able to choose where to intall it, that's
- * using the placeholder @extschema@.
- */
- if (control->relocatable)
- {
- List *search_path = fetch_search_path(false);
- Oid first_schema, target_schema;
-
- if (!execute_sql_string(sql))
- ereport(ERROR,
- (errcode(ERRCODE_DATA_EXCEPTION),
- errmsg("could not execute sql file: '%s'", filename)));
-
- /*
- * CREATE EXTENSION foo WITH SCHEMA bar;
- *
- * The extension is relocatable, so we run its install script
- * and it has to install all objects into the same schema. Then
- * we relocate all the objects to the target SCHEMA bar,
- * ERRORing out if some objects are not in the same schema than
- * others, that's doing:
- *
- * ALTER EXTENSION foo SET SCHEMA bar;
- *
- * We skip this step if the target schema happens to be the
- * first schema of the current search_path.
- */
- first_schema = linitial_oid(search_path);
- target_schema = LookupCreationNamespace(schema);
- list_free(search_path);
-
- if (first_schema != target_schema)
- AlterExtensionNamespace_oid(extensionoid, target_schema);
- }
- else
- {
- /*
- * Prepare the replacements we use in execute_sql_file(). Even if
- * the schema has not been specified by the user, we still have to
- * set @extschema@ to 'public' so that extension scripts can rely on
- * this placeholder.
- */
- sql = text_to_cstring(
- DatumGetTextPP(
- DirectFunctionCall3(replace_text,
- CStringGetTextDatum(sql),
- CStringGetTextDatum("@extschema@"),
- CStringGetTextDatum(schema))));
-
- if (!execute_sql_string(sql))
- ereport(ERROR,
- (errcode(ERRCODE_DATA_EXCEPTION),
- errmsg("could not execute sql file: '%s'", filename)));
- }
- }
- PG_CATCH();
- {
- create_extension = false;
- PG_RE_THROW();
- }
- PG_END_TRY();
/*
* the extension depends on the schema we used, record that
--- 779,784 ----
***************
*** 667,682 **** CreateExtension(CreateExtensionStmt *stmt)
recordDependencyOn(&CreateExtensionAddress, &nsp, DEPENDENCY_NORMAL);
}
! if (reset_cmsgs)
! SetConfigOption("client_min_messages",
! old_cmsgs, PGC_SUSET, PGC_S_SESSION);
! if (reset_lmsgs)
! SetConfigOption("log_min_messages",
! old_lmsgs, PGC_SUSET, PGC_S_SESSION);
!
! /* reset the current_extension dependency tracker */
! create_extension = false;
return;
}
--- 793,808 ----
recordDependencyOn(&CreateExtensionAddress, &nsp, DEPENDENCY_NORMAL);
}
! /*
! * When CREATE WRAPPER EXTENSION is used, skip the script
! */
! if (stmt->wrapper)
! {
! elog(DEBUG1, "Skip the script for a WRAPPER extension");
! return;
! }
+ execute_extension_script(control, schema, true, user_data);
return;
}
***************
*** 832,837 **** get_extension_name(Oid ext_oid)
--- 958,1016 ----
}
/*
+ * get_extension_version - given an extension OID, look up the version
+ *
+ * Returns a palloc'd string, or NULL if no such extension.
+ */
+ char *
+ get_extension_version(Oid ext_oid)
+ {
+ char *result;
+ Relation rel;
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+ ScanKeyData entry[1];
+
+ /*
+ * Search pg_extension. We use a heapscan here even though there is an
+ * index on oid, on the theory that pg_extension will usually have just a
+ * few entries and so an indexed lookup is a waste of effort.
+ */
+ rel = heap_open(ExtensionRelationId, AccessShareLock);
+
+ ScanKeyInit(&entry[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(ext_oid));
+ scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
+ tuple = heap_getnext(scandesc, ForwardScanDirection);
+
+ /* We assume that there can be at most one matching tuple */
+ if (HeapTupleIsValid(tuple))
+ {
+ bool isnull;
+ Datum d_version;
+
+ d_version = heap_getattr(tuple,
+ Anum_pg_extension_extversion,
+ rel->rd_att,
+ &isnull);
+
+ if (isnull)
+ result = NULL;
+ else
+ result = pstrdup(TextDatumGetCString(d_version));
+ }
+ else
+ result = NULL;
+
+ heap_endscan(scandesc);
+ heap_close(rel, AccessShareLock);
+
+ return result;
+ }
+
+ /*
* extension_relocatable_p
*
* Returns true when the extension is marked 'relocatable'
***************
*** 1120,1126 **** pg_extensions(PG_FUNCTION_ARGS)
*/
control = parse_extension_control_file(
get_extension_name_from_control_filename(de->d_name),
! get_extension_absolute_path(de->d_name), false);
memset(values, 0, sizeof(values));
MemSet(nulls, false, sizeof(nulls));
--- 1299,1305 ----
*/
control = parse_extension_control_file(
get_extension_name_from_control_filename(de->d_name),
! get_extension_absolute_path(de->d_name), false, NULL);
memset(values, 0, sizeof(values));
MemSet(nulls, false, sizeof(nulls));
***************
*** 1250,1256 **** AlterExtensionNamespace(List *name, const char *newschema)
void
AlterExtensionNamespace_oid(Oid extensionOid, Oid nspOid)
{
! Oid oldNspOid;
ObjectAddress *object;
ObjectAddresses *targetObjects;
int i;
--- 1429,1435 ----
void
AlterExtensionNamespace_oid(Oid extensionOid, Oid nspOid)
{
! Oid oldNspOid = InvalidOid;
ObjectAddress *object;
ObjectAddresses *targetObjects;
int i;
***************
*** 1270,1282 **** AlterExtensionNamespace_oid(Oid extensionOid, Oid nspOid)
object->objectId = extensionOid;
object->objectSubId = 0;
- /*
- * At CREATE EXTENSION time the dependency towards the schema where live
- * the extension's objects is not registered yet, so we get InvalidOid
- * here.
- */
- oldNspOid = get_extension_namespace(extensionOid);
-
targetObjects = listDependentObjects(object);
for (i = 0; i < targetObjects->numrefs; i++)
--- 1449,1454 ----
***************
*** 1313,1315 **** AlterExtensionNamespace_oid(Oid extensionOid, Oid nspOid)
--- 1485,1609 ----
free_object_addresses(targetObjects);
}
+
+ /*
+ * ALTER EXTENSION name UPGRADE
+ *
+ * Only superusers can upgrade an extension.
+ */
+ void
+ UpgradeExtension(AlterExtensionStmt *stmt)
+ {
+ char *version, *nspname;
+ Oid extensionoid = InvalidOid;
+ ExtensionControlFile *control;
+
+ /* Must be super user */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to upgrade extension \"%s\"",
+ stmt->extname),
+ errhint("Must be superuser to upgrade an extension.")));
+
+ /* We can only upgrade installed extension */
+ extensionoid = get_extension_oid(stmt->extname, false);
+ nspname = get_namespace_name(get_extension_namespace(extensionoid));
+ version = get_extension_version(extensionoid);
+ control = read_extension_control_file(stmt->extname, true, version);
+
+ /*
+ * Prepare the same script execution context as in CREATE EXTENSION
+ */
+ CreateExtensionAddress.classId = ExtensionRelationId;
+ CreateExtensionAddress.objectId = extensionoid;
+ CreateExtensionAddress.objectSubId = 0;
+
+ create_extension = true;
+ create_extension_with_user_data = false;
+
+ /*
+ * When doing and extension UPGRADE the user data is certainly there
+ * already, so the user_data argument is 'false' here.
+ */
+ execute_extension_script(control, nspname, false, false);
+
+ /* Now upgrade the version in the catalogs */
+ {
+ Relation rel;
+ HeapScanDesc scandesc;
+ ScanKeyData entry[1];
+ HeapTuple tup, newtup;
+ Datum *values;
+ bool *nulls;
+ bool *replaces;
+
+ rel = heap_open(ExtensionRelationId, RowExclusiveLock);
+
+ ScanKeyInit(&entry[0],
+ Anum_pg_extension_extname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ CStringGetDatum(stmt->extname));
+ scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
+ tup = heap_getnext(scandesc, ForwardScanDirection);
+
+ values = palloc0(rel->rd_att->natts * sizeof(Datum));
+ nulls = palloc0(rel->rd_att->natts * sizeof(bool));
+ replaces = palloc0(rel->rd_att->natts * sizeof(bool));
+ values[Anum_pg_extension_extversion - 1] =
+ CStringGetTextDatum(control->version);
+ replaces[Anum_pg_extension_extversion - 1] = true;
+ newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);
+
+ /* Perform actual update */
+ simple_heap_update(rel, &tup->t_self, newtup);
+ CatalogUpdateIndexes(rel, newtup);
+
+ /* Release memory */
+ pfree(values);
+ pfree(nulls);
+ pfree(replaces);
+
+ heap_endscan(scandesc);
+ heap_close(rel, RowExclusiveLock);
+ }
+ }
+
+ /*
+ * ALTER OBJECT SET EXTENSION
+ *
+ * This form allows for upgrading from previous PostgreSQL version to one
+ * supporting extensions, or to upgrade user objects to get to use the
+ * extension infrastructure.
+ *
+ * All we have to do is record an INTERNAL dependency between the selected
+ * object and the extension, which must of course already exist.
+ */
+ void
+ AlterObjectExtension(const char *extname,
+ Oid classId, Oid objectId, Oid objectSubId)
+ {
+ Oid extensionoid = InvalidOid;
+ ObjectAddress *extension, *object;
+
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to SET EXTENSION"))));
+
+ extensionoid = get_extension_oid(extname, false);
+
+ extension = (ObjectAddress *)palloc(sizeof(ObjectAddress));
+ extension->classId = ExtensionRelationId;
+ extension->objectId = extensionoid;
+ extension->objectSubId = 0;
+
+ object = (ObjectAddress *)palloc(sizeof(ObjectAddress));
+ object->classId = classId;
+ object->objectId = objectId;
+ object->objectSubId = objectSubId;
+
+ recordDependencyOn(object, extension, DEPENDENCY_INTERNAL);
+
+ return;
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1950,1955 **** AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
--- 1950,1979 ----
return oldNspOid;
}
+ /*
+ * Execute ALTER FUNCTION/AGGREGATE SET EXTENSION
+ *
+ * These commands are identical except for the lookup procedure, so share code.
+ */
+ void
+ AlterFunctionExtension(List *name, List *argtypes, bool isagg,
+ const char *extname)
+ {
+ Oid procOid;
+
+ /* get function OID */
+ if (isagg)
+ procOid = LookupAggNameTypeNames(name, argtypes, false);
+ else
+ procOid = LookupFuncNameTypeNames(name, argtypes, false);
+
+ /* check permissions on function */
+ if (!pg_proc_ownercheck(procOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ NameListToString(name));
+
+ AlterObjectExtension(extname, ProcedureRelationId, procOid, 0);
+ }
/*
* ExecuteDoStmt
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 2065,2070 **** AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
--- 2065,2089 ----
}
/*
+ * ALTER OPERATOR CLASS any_name USING access_method SET EXTENSION name
+ */
+ void
+ AlterOpClassExtension(List *name, List *argam, const char *extname)
+ {
+ Oid amOid;
+ char *access_method = linitial(argam);
+ Oid oid;
+
+ Assert(list_length(argam) == 1);
+
+ /* Look up the opclass. */
+ amOid = get_am_oid(access_method, false);
+ oid = get_opclass_oid(amOid, name, false);
+
+ AlterObjectExtension(extname, OperatorClassRelationId, oid, 0);
+ }
+
+ /*
* Change opfamily owner by name
*/
void
***************
*** 2281,2283 **** AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
--- 2300,2321 ----
heap_close(rel, NoLock);
return oldNspOid;
}
+
+ /*
+ * ALTER OPERATOR FAMILY any_name USING access_method SET EXTENSION name
+ */
+ void
+ AlterOpFamilyExtension(List *name, List *argam, const char *extname)
+ {
+ Oid amOid;
+ char *access_method = linitial(argam);
+ Oid oid;
+
+ Assert(list_length(argam) == 1);
+
+ /* Look up the opfamily */
+ amOid = get_am_oid(access_method, false);
+ oid = get_opfamily_oid(amOid, name, false);
+
+ AlterObjectExtension(extname, OperatorFamilyRelationId, oid, 0);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 43,48 ****
--- 43,49 ----
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
+ #include "commands/extension.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
***************
*** 507,509 **** AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
--- 508,529 ----
return oldNspOid;
}
+
+ /*
+ * Execute ALTER OPERATOR SET EXTENSION
+ */
+ void
+ AlterOperatorExtension(List *names, List *argtypes, const char *extname)
+ {
+ List *operatorName = names;
+ TypeName *typeName1 = (TypeName *) linitial(argtypes);
+ TypeName *typeName2 = (TypeName *) lsecond(argtypes);
+ Oid operOid;
+
+ Assert(list_length(argtypes) == 2);
+ operOid = LookupOperNameTypeNames(NULL, operatorName,
+ typeName1, typeName2,
+ false, -1);
+
+ AlterObjectExtension(extname, OperatorRelationId, operOid, 0);
+ }
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 8268,8273 **** AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
--- 8268,8290 ----
}
/*
+ * Execute ALTER TABLE|SEQUENCE|VIEW SET EXTENSION
+ *
+ * Note: caller must have checked ownership of the relation already
+ */
+ void
+ AlterTableExtension(RangeVar *relation, const char *extname)
+ {
+ Relation rel;
+ Oid relid;
+
+ rel = relation_openrv(relation, AccessExclusiveLock);
+ relid = RelationGetRelid(rel);
+ AlterObjectExtension(extname, RelationRelationId, relid, 0);
+ relation_close(rel, NoLock);
+ }
+
+ /*
* Move all indexes for the specified relation to another namespace.
*
* Note: we assume adequate permission checking was done by the caller,
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 448,453 **** AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
--- 448,463 ----
return oldNspOid;
}
+ /*
+ * ALTER TEXT SEARCH PARSER any_name SET EXTENSION name
+ */
+ void
+ AlterTSParserExtension(List *name, const char *extname)
+ {
+ Oid prsId = get_ts_parser_oid(name, false);
+ AlterObjectExtension(extname, TSParserRelationId, prsId, 0);
+ }
+
/* ---------------------- TS Dictionary commands -----------------------*/
/*
***************
*** 732,737 **** AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
--- 742,757 ----
}
/*
+ * ALTER TEXT SEARCH DICTIONARY any_name SET EXTENSION name
+ */
+ void
+ AlterTSDictionaryExtension(List *name, const char *extname)
+ {
+ Oid dictId = get_ts_dict_oid(name, false);
+ AlterObjectExtension(extname, TSDictionaryRelationId, dictId, 0);
+ }
+
+ /*
* DROP TEXT SEARCH DICTIONARY
*/
void
***************
*** 1265,1270 **** AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
--- 1285,1300 ----
}
/*
+ * ALTER TEXT SEARCH TEMPLATE any_name SET EXTENSION name
+ */
+ void
+ AlterTSTemplateExtension(List *name, const char *extname)
+ {
+ Oid tmplId = get_ts_template_oid(name, false);
+ AlterObjectExtension(extname, TSTemplateRelationId, tmplId, 0);
+ }
+
+ /*
* DROP TEXT SEARCH TEMPLATE
*/
void
***************
*** 1719,1724 **** AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
--- 1749,1764 ----
}
/*
+ * ALTER TEXT SEARCH CONFIGURATION any_name SET EXTENSION name
+ */
+ void
+ AlterTSConfigurationExtension(List *name, const char *extname)
+ {
+ Oid cfgId = get_ts_config_oid(name, false);
+ AlterObjectExtension(extname, TSConfigRelationId, cfgId, 0);
+ }
+
+ /*
* DROP TEXT SEARCH CONFIGURATION
*/
void
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 2923,2925 **** AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
--- 2923,2941 ----
return oldNspOid;
}
+
+ /*
+ * Execute ALTER TYPE SET EXTENSION
+ */
+ void
+ AlterTypeExtension(List *names, const char *extname)
+ {
+ TypeName *typename;
+ Oid typeOid;
+
+ /* Make a TypeName so we can use standard type lookup machinery */
+ typename = makeTypeNameFromNameList(names);
+ typeOid = typenameTypeId(NULL, typename);
+
+ AlterObjectExtension(extname, TypeRelationId, typeOid, 0);
+ }
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 2826,2831 **** _copyAlterObjectSchemaStmt(AlterObjectSchemaStmt *from)
--- 2826,2846 ----
return newnode;
}
+ static AlterObjectExtensionStmt *
+ _copyAlterObjectExtensionStmt(AlterObjectExtensionStmt *from)
+ {
+ AlterObjectExtensionStmt *newnode = makeNode(AlterObjectExtensionStmt);
+
+ COPY_SCALAR_FIELD(objectType);
+ COPY_NODE_FIELD(relation);
+ COPY_NODE_FIELD(object);
+ COPY_NODE_FIELD(objarg);
+ COPY_STRING_FIELD(addname);
+ COPY_STRING_FIELD(extname);
+
+ return newnode;
+ }
+
static AlterOwnerStmt *
_copyAlterOwnerStmt(AlterOwnerStmt *from)
{
***************
*** 3156,3161 **** _copyCreateExtensionStmt(CreateExtensionStmt *from)
--- 3171,3177 ----
CreateExtensionStmt *newnode = makeNode(CreateExtensionStmt);
COPY_STRING_FIELD(extname);
+ COPY_SCALAR_FIELD(wrapper);
COPY_NODE_FIELD(options);
return newnode;
***************
*** 3173,3178 **** _copyDropExtensionStmt(DropExtensionStmt *from)
--- 3189,3204 ----
return newnode;
}
+ static AlterExtensionStmt *
+ _copyAlterExtensionStmt(AlterExtensionStmt *from)
+ {
+ AlterExtensionStmt *newnode = makeNode(AlterExtensionStmt);
+
+ COPY_STRING_FIELD(extname);
+
+ return newnode;
+ }
+
static CreateTableSpaceStmt *
_copyCreateTableSpaceStmt(CreateTableSpaceStmt *from)
{
***************
*** 3694,3699 **** copyObject(void *from)
--- 3720,3727 ----
/* Guard against stack overflow due to overly complex expressions */
check_stack_depth();
+ Assert(nodeTag(from) <= T_InlineCodeBlock);
+
switch (nodeTag(from))
{
/*
***************
*** 4104,4109 **** copyObject(void *from)
--- 4132,4140 ----
case T_AlterObjectSchemaStmt:
retval = _copyAlterObjectSchemaStmt(from);
break;
+ case T_AlterObjectExtensionStmt:
+ retval = _copyAlterObjectExtensionStmt(from);
+ break;
case T_AlterOwnerStmt:
retval = _copyAlterOwnerStmt(from);
break;
***************
*** 4197,4202 **** copyObject(void *from)
--- 4228,4236 ----
case T_DropExtensionStmt:
retval = _copyDropExtensionStmt(from);
break;
+ case T_AlterExtensionStmt:
+ retval = _copyAlterExtensionStmt(from);
+ break;
case T_AlterTableSpaceOptionsStmt:
retval = _copyAlterTableSpaceOptionsStmt(from);
break;
***************
*** 4392,4398 **** copyObject(void *from)
break;
default:
! elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
retval = from; /* keep compiler quiet */
break;
}
--- 4426,4432 ----
break;
default:
! elog(ERROR, "unrecognized BAR node type: %d", (int) nodeTag(from));
retval = from; /* keep compiler quiet */
break;
}
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 1325,1330 **** _equalAlterObjectSchemaStmt(AlterObjectSchemaStmt *a, AlterObjectSchemaStmt *b)
--- 1325,1343 ----
}
static bool
+ _equalAlterObjectExtensionStmt(AlterObjectExtensionStmt *a, AlterObjectExtensionStmt *b)
+ {
+ COMPARE_SCALAR_FIELD(objectType);
+ COMPARE_NODE_FIELD(relation);
+ COMPARE_NODE_FIELD(object);
+ COMPARE_NODE_FIELD(objarg);
+ COMPARE_STRING_FIELD(addname);
+ COMPARE_STRING_FIELD(extname);
+
+ return true;
+ }
+
+ static bool
_equalAlterOwnerStmt(AlterOwnerStmt *a, AlterOwnerStmt *b)
{
COMPARE_SCALAR_FIELD(objectType);
***************
*** 1617,1622 **** static bool
--- 1630,1636 ----
_equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
{
COMPARE_STRING_FIELD(extname);
+ COMPARE_SCALAR_FIELD(wrapper);
COMPARE_NODE_FIELD(options);
return true;
***************
*** 1633,1638 **** _equalDropExtensionStmt(DropExtensionStmt *a, DropExtensionStmt *b)
--- 1647,1660 ----
}
static bool
+ _equalAlterExtensionStmt(AlterExtensionStmt *a, AlterExtensionStmt *b)
+ {
+ COMPARE_STRING_FIELD(extname);
+
+ return true;
+ }
+
+ static bool
_equalAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *a,
AlterTableSpaceOptionsStmt *b)
{
***************
*** 2723,2728 **** equal(void *a, void *b)
--- 2745,2753 ----
case T_AlterObjectSchemaStmt:
retval = _equalAlterObjectSchemaStmt(a, b);
break;
+ case T_AlterObjectExtensionStmt:
+ retval = _equalAlterObjectExtensionStmt(a, b);
+ break;
case T_AlterOwnerStmt:
retval = _equalAlterOwnerStmt(a, b);
break;
***************
*** 2810,2815 **** equal(void *a, void *b)
--- 2835,2843 ----
case T_DropExtensionStmt:
retval = _equalDropExtensionStmt(a, b);
break;
+ case T_AlterExtensionStmt:
+ retval = _equalAlterExtensionStmt(a, b);
+ break;
case T_CreateTableSpaceStmt:
retval = _equalCreateTableSpaceStmt(a, b);
break;
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 183,190 **** static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
%type <node> stmt schema_stmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
! AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
! AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt
AlterDefaultPrivilegesStmt DefACLAction
--- 183,191 ----
%type <node> stmt schema_stmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
! AlterExtensionStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
! AlterObjectSchemaStmt AlterObjectExtensionStmt AlterOwnerStmt
! AlterSeqStmt AlterTableStmt
AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt
AlterDefaultPrivilegesStmt DefACLAction
***************
*** 537,543 **** static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
TRUNCATE TRUSTED TYPE_P
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
! UPDATE USER USING
VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
VERBOSE VERSION_P VIEW VOLATILE
--- 538,544 ----
TRUNCATE TRUSTED TYPE_P
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
! UPDATE UPGRADE USER USING
VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
VERBOSE VERSION_P VIEW VOLATILE
***************
*** 654,664 **** stmt :
--- 655,667 ----
| AlterDefaultPrivilegesStmt
| AlterDomainStmt
| AlterEnumStmt
+ | AlterExtensionStmt
| AlterFdwStmt
| AlterForeignServerStmt
| AlterFunctionStmt
| AlterGroupStmt
| AlterObjectSchemaStmt
+ | AlterObjectExtensionStmt
| AlterOwnerStmt
| AlterSeqStmt
| AlterTableStmt
***************
*** 3088,3106 **** opt_procedural:
/*****************************************************************************
*
* QUERY:
! * CREATE EXTENSION extension
* [ [ WITH ] [ [ NO ] USER DATA ]
* [ SCHEMA [=] schema ] ]
*
*****************************************************************************/
! CreateExtensionStmt: CREATE EXTENSION name opt_with create_extension_opt_list
{
CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
n->extname = $3;
n->options = $5;
$$ = (Node *) n;
}
;
create_extension_opt_list:
--- 3091,3120 ----
/*****************************************************************************
*
* QUERY:
! * CREATE [ WRAPPER ] EXTENSION extension
* [ [ WITH ] [ [ NO ] USER DATA ]
+ * [ SYSID [=] oid ] ]
* [ SCHEMA [=] schema ] ]
*
*****************************************************************************/
! CreateExtensionStmt:
! CREATE EXTENSION name opt_with create_extension_opt_list
{
CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
n->extname = $3;
+ n->wrapper = false;
n->options = $5;
$$ = (Node *) n;
}
+ | CREATE WRAPPER EXTENSION name opt_with create_extension_opt_list
+ {
+ CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
+ n->extname = $4;
+ n->wrapper = true;
+ n->options = $6;
+ $$ = (Node *) n;
+ }
;
create_extension_opt_list:
***************
*** 3124,3129 **** create_extension_opt_item:
--- 3138,3147 ----
{
$$ = makeDefElem("schema", (Node *)makeString($3));
}
+ | SYSID opt_equal Iconst
+ {
+ $$ = makeDefElem("sysid", (Node *)makeInteger($3));
+ }
;
/*****************************************************************************
***************
*** 3154,3159 **** DropExtensionStmt: DROP EXTENSION name opt_drop_behavior
--- 3172,3192 ----
/*****************************************************************************
*
* QUERY:
+ * ALTER EXTENSION <extension> UPGRADE
+ *
+ *****************************************************************************/
+
+ AlterExtensionStmt: ALTER EXTENSION name UPGRADE
+ {
+ AlterExtensionStmt *n = makeNode(AlterExtensionStmt);
+ n->extname = $3;
+ $$ = (Node *) n;
+ }
+ ;
+
+ /*****************************************************************************
+ *
+ * QUERY:
* CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/'
*
*****************************************************************************/
***************
*** 6249,6254 **** AlterObjectSchemaStmt:
--- 6282,6421 ----
/*****************************************************************************
*
+ * ALTER THING name SET EXTENSION name
+ *
+ *****************************************************************************/
+
+ AlterObjectExtensionStmt:
+ ALTER AGGREGATE func_name aggr_args SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_AGGREGATE;
+ n->object = $3;
+ n->objarg = $4;
+ n->extname = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER CONVERSION_P any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_CONVERSION;
+ n->object = $3;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER DOMAIN_P any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_DOMAIN;
+ n->object = $3;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER FUNCTION function_with_argtypes SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_FUNCTION;
+ n->object = $3->funcname;
+ n->objarg = $3->funcargs;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR any_operator oper_argtypes SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_OPERATOR;
+ n->object = $3;
+ n->objarg = $4;
+ n->extname = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR CLASS any_name USING access_method SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_OPCLASS;
+ n->object = $4;
+ n->objarg = list_make1($6);
+ n->extname = $9;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR FAMILY any_name USING access_method SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_OPFAMILY;
+ n->object = $4;
+ n->objarg = list_make1($6);
+ n->extname = $9;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE relation_expr SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_TABLE;
+ n->relation = $3;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH PARSER any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_TSPARSER;
+ n->object = $5;
+ n->extname = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH DICTIONARY any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_TSDICTIONARY;
+ n->object = $5;
+ n->extname = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH TEMPLATE any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_TSTEMPLATE;
+ n->object = $5;
+ n->extname = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_TSCONFIGURATION;
+ n->object = $5;
+ n->extname = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE qualified_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_SEQUENCE;
+ n->relation = $3;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW qualified_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_VIEW;
+ n->relation = $3;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER TYPE_P any_name SET EXTENSION name
+ {
+ AlterObjectExtensionStmt *n = makeNode(AlterObjectExtensionStmt);
+ n->objectType = OBJECT_TYPE;
+ n->object = $3;
+ n->extname = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+ /*****************************************************************************
+ *
* ALTER THING name OWNER TO newname
*
*****************************************************************************/
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 162,171 **** check_xact_readonly(Node *parsetree)
--- 162,173 ----
case T_AlterDatabaseStmt:
case T_AlterDatabaseSetStmt:
case T_AlterDomainStmt:
+ case T_AlterExtensionStmt:
case T_AlterFunctionStmt:
case T_AlterRoleStmt:
case T_AlterRoleSetStmt:
case T_AlterObjectSchemaStmt:
+ case T_AlterObjectExtensionStmt:
case T_AlterOwnerStmt:
case T_AlterSeqStmt:
case T_AlterTableStmt:
***************
*** 569,574 **** standard_ProcessUtility(Node *parsetree,
--- 571,580 ----
DropExtension((DropExtensionStmt *) parsetree);
break;
+ case T_AlterExtensionStmt:
+ UpgradeExtension((AlterExtensionStmt *) parsetree);
+ break;
+
case T_CreateTableSpaceStmt:
PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
***************
*** 718,723 **** standard_ProcessUtility(Node *parsetree,
--- 724,733 ----
ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
break;
+ case T_AlterObjectExtensionStmt:
+ ExecAlterObjectExtensionStmt((AlterObjectExtensionStmt *) parsetree);
+ break;
+
case T_AlterOwnerStmt:
ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
***************
*** 1528,1533 **** CreateCommandTag(Node *parsetree)
--- 1538,1547 ----
tag = "DROP EXTENSION";
break;
+ case T_AlterExtensionStmt:
+ tag = "ALTER EXTENSION";
+ break;
+
case T_CreateTableSpaceStmt:
tag = "CREATE TABLESPACE";
break;
***************
*** 1764,1769 **** CreateCommandTag(Node *parsetree)
--- 1778,1837 ----
}
break;
+ case T_AlterObjectExtensionStmt:
+ switch (((AlterObjectExtensionStmt *) parsetree)->objectType)
+ {
+ case OBJECT_AGGREGATE:
+ tag = "ALTER AGGREGATE";
+ break;
+ case OBJECT_CONVERSION:
+ tag = "ALTER CONVERSION";
+ break;
+ case OBJECT_DOMAIN:
+ tag = "ALTER DOMAIN";
+ break;
+ case OBJECT_FUNCTION:
+ tag = "ALTER FUNCTION";
+ break;
+ case OBJECT_OPERATOR:
+ tag = "ALTER OPERATOR";
+ break;
+ case OBJECT_OPCLASS:
+ tag = "ALTER OPERATOR CLASS";
+ break;
+ case OBJECT_OPFAMILY:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
+ case OBJECT_SEQUENCE:
+ tag = "ALTER SEQUENCE";
+ break;
+ case OBJECT_TABLE:
+ tag = "ALTER TABLE";
+ break;
+ case OBJECT_TYPE:
+ tag = "ALTER TYPE";
+ break;
+ case OBJECT_TSPARSER:
+ tag = "ALTER TEXT SEARCH PARSER";
+ break;
+ case OBJECT_TSDICTIONARY:
+ tag = "ALTER TEXT SEARCH DICTIONARY";
+ break;
+ case OBJECT_TSTEMPLATE:
+ tag = "ALTER TEXT SEARCH TEMPLATE";
+ break;
+ case OBJECT_TSCONFIGURATION:
+ tag = "ALTER TEXT SEARCH CONFIGURATION";
+ break;
+ case OBJECT_VIEW:
+ tag = "ALTER VIEW";
+ break;
+ default:
+ tag = "???";
+ break;
+ }
+ break;
+
case T_AlterOwnerStmt:
switch (((AlterOwnerStmt *) parsetree)->objectType)
{
***************
*** 2349,2354 **** GetCommandLogLevel(Node *parsetree)
--- 2417,2426 ----
lev = LOGSTMT_DDL;
break;
+ case T_AlterExtensionStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_CreateTableSpaceStmt:
lev = LOGSTMT_DDL;
break;
***************
*** 2431,2436 **** GetCommandLogLevel(Node *parsetree)
--- 2503,2512 ----
lev = LOGSTMT_DDL;
break;
+ case T_AlterObjectExtensionStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_AlterOwnerStmt:
lev = LOGSTMT_DDL;
break;
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 2394,2401 **** getExtensions(int *numExtensions)
int i_tableoid;
int i_oid;
int i_extname;
int i_extversion;
- int i_extcclass;
int i_nspname;
/*
--- 2394,2401 ----
int i_tableoid;
int i_oid;
int i_extname;
+ int i_relocatable;
int i_extversion;
int i_nspname;
/*
***************
*** 2418,2424 **** getExtensions(int *numExtensions)
*/
appendPQExpBuffer(query,
"SELECT x.tableoid, x.oid, "
! "x.extname, x.extversion, x.custom_class, n.nspname "
"FROM pg_extension x "
"JOIN pg_depend d ON d.objid = x.oid "
"and d.refclassid = 'pg_catalog.pg_namespace'::regclass "
--- 2418,2424 ----
*/
appendPQExpBuffer(query,
"SELECT x.tableoid, x.oid, "
! "x.extname, x.relocatable, x.extversion, n.nspname "
"FROM pg_extension x "
"JOIN pg_depend d ON d.objid = x.oid "
"and d.refclassid = 'pg_catalog.pg_namespace'::regclass "
***************
*** 2434,2441 **** getExtensions(int *numExtensions)
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_extname = PQfnumber(res, "extname");
i_extversion = PQfnumber(res, "extversion");
- i_extcclass = PQfnumber(res, "custom_class");
i_nspname = PQfnumber(res, "nspname");
for (i = 0; i < ntups; i++)
--- 2434,2441 ----
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_extname = PQfnumber(res, "extname");
+ i_relocatable = PQfnumber(res, "relocatable");
i_extversion = PQfnumber(res, "extversion");
i_nspname = PQfnumber(res, "nspname");
for (i = 0; i < ntups; i++)
***************
*** 2445,2452 **** getExtensions(int *numExtensions)
extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&extinfo[i].dobj);
extinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_extname));
extinfo[i].extversion = strdup(PQgetvalue(res, i, i_extversion));
- extinfo[i].custom_class = strdup(PQgetvalue(res, i, i_extcclass));
extinfo[i].namespace = strdup(PQgetvalue(res, i, i_nspname));
}
--- 2445,2452 ----
extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&extinfo[i].dobj);
extinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_extname));
+ extinfo[i].relocatable = strdup(PQgetvalue(res, i, i_relocatable));
extinfo[i].extversion = strdup(PQgetvalue(res, i, i_extversion));
extinfo[i].namespace = strdup(PQgetvalue(res, i, i_nspname));
}
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
***************
*** 137,144 **** typedef struct _extensionInfo
{
DumpableObject dobj;
char *extname;
char *extversion;
- char *custom_class;
char *namespace;
} ExtensionInfo;
--- 137,144 ----
{
DumpableObject dobj;
char *extname;
+ char *relocatable;
char *extversion;
char *namespace;
} ExtensionInfo;
*** a/src/include/commands/alter.h
--- b/src/include/commands/alter.h
***************
*** 21,26 ****
--- 21,27 ----
extern void ExecRenameStmt(RenameStmt *stmt);
extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
+ extern void ExecAlterObjectExtensionStmt(AlterObjectExtensionStmt *stmt);
extern Oid AlterObjectNamespace(Relation rel, int cacheId,
Oid classId, Oid objid, Oid nspId,
int Anum_name, int Anum_namespace, int Anum_owner,
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 24,28 **** extern void AlterConversionOwner(List *name, Oid newOwnerId);
--- 24,29 ----
extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
extern void AlterConversionNamespace(List *name, const char *newschema);
extern Oid AlterConversionNamespace_oid(Oid convOid, Oid newNspOid);
+ extern void AlterConversionExtension(List *name, const char *extname);
#endif /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 67,72 **** extern void DropCastById(Oid castOid);
--- 67,74 ----
extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
const char *newschema);
extern Oid AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
+ extern void AlterFunctionExtension(List *name, List *argtypes, bool isagg,
+ const char *extname);
extern void ExecuteDoStmt(DoStmt *stmt);
extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
***************
*** 82,87 **** extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
--- 84,90 ----
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
extern Oid AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
+ extern void AlterOperatorExtension(List *names, List *argtypes, const char *extname);
/* commands/aggregatecmds.c */
extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 106,116 **** extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwne
--- 109,121 ----
extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
extern Oid AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
+ extern void AlterOpClassExtension(List *name, List *argam, const char *extname);
extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
extern Oid get_am_oid(const char *amname, bool missing_ok);
extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
extern Oid AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
+ extern void AlterOpFamilyExtension(List *name, List *argam, const char *extname);
/* commands/tsearchcmds.c */
extern void DefineTSParser(List *names, List *parameters);
***************
*** 120,125 **** extern void RemoveTSParsers(DropStmt *drop);
--- 125,131 ----
extern void RemoveTSParserById(Oid prsId);
extern void AlterTSParserNamespace(List *name, const char *newschema);
extern Oid AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
+ extern void AlterTSParserExtension(List *name, const char *extname);
extern void DefineTSDictionary(List *names, List *parameters);
extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 129,139 **** extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
--- 135,147 ----
extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
extern Oid AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
+ extern void AlterTSDictionaryExtension(List *name, const char *extname);
extern void DefineTSTemplate(List *names, List *parameters);
extern void RenameTSTemplate(List *oldname, const char *newname);
extern void AlterTSTemplateNamespace(List *name, const char *newschema);
extern Oid AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
+ extern void AlterTSTemplateExtension(List *name, const char *extname);
extern void RemoveTSTemplates(DropStmt *stmt);
extern void RemoveTSTemplateById(Oid tmplId);
***************
*** 146,151 **** extern void RemoveTSConfigurationById(Oid cfgId);
--- 154,160 ----
extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationExtension(List *name, const char *extname);
extern text *serialize_deflist(List *deflist);
extern List *deserialize_deflist(Datum txt);
*** a/src/include/commands/extension.h
--- b/src/include/commands/extension.h
***************
*** 40,45 **** typedef struct ExtensionControlFile
--- 40,46 ----
char *comment; /* the control file can also contain a comment */
int encoding; /* encoding of the given script */
bool relocatable; /* when true, ALTER EXTENSION SET SCHEMA is supported */
+ char *upgrade; /* filename of the upgrade script to execute, or NULL */
} ExtensionControlFile;
/* expansible list of extensions */
***************
*** 59,71 **** typedef struct extension_objects_fctx
--- 60,76 ----
extern void CreateExtension(CreateExtensionStmt *stmt);
extern void DropExtension(DropExtensionStmt *stmt);
+ extern void UpgradeExtension(AlterExtensionStmt *stmt);
extern Oid get_extension_oid(const char *extname, bool missing_ok);
extern char *get_extension_name(Oid ext_oid);
+ extern char *get_extension_version(Oid ext_oid);
extern bool extension_relocatable_p(Oid ext_oid);
extern void RemoveExtensionById(Oid extId);
extern void AlterExtensionNamespace(List *name, const char *newschema);
extern void AlterExtensionNamespace_oid(Oid extensionOid, Oid nspOid);
+ extern void AlterObjectExtension(const char *extname,
+ Oid classId, Oid objectId, Oid objectSubId);
#endif /* EXTENSION_H */
*** a/src/include/commands/tablecmds.h
--- b/src/include/commands/tablecmds.h
***************
*** 38,43 **** extern Oid AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
--- 38,45 ----
Oid oldNspOid, Oid newNspOid,
bool hasDependEntry);
+ extern void AlterTableExtension(RangeVar *relation, const char *extname);
+
extern void CheckTableNotInUse(Relation rel, const char *stmt);
extern void ExecuteTruncate(TruncateStmt *stmt);
*** a/src/include/commands/typecmds.h
--- b/src/include/commands/typecmds.h
***************
*** 45,49 **** extern Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid);
--- 45,50 ----
extern Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool isImplicitArray,
bool errorOnTableType);
+ extern void AlterTypeExtension(List *names, const char *extname);
#endif /* TYPECMDS_H */
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 334,339 **** typedef enum NodeTag
--- 334,340 ----
T_CreateTableSpaceStmt,
T_DropTableSpaceStmt,
T_AlterObjectSchemaStmt,
+ T_AlterObjectExtensionStmt,
T_AlterOwnerStmt,
T_DropOwnedStmt,
T_ReassignOwnedStmt,
***************
*** 355,360 **** typedef enum NodeTag
--- 356,362 ----
T_SecLabelStmt,
T_CreateExtensionStmt,
T_DropExtensionStmt,
+ T_AlterExtensionStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1499,1504 **** typedef struct CreateExtensionStmt
--- 1499,1505 ----
{
NodeTag type;
char *extname;
+ bool wrapper; /* Create a wrapper extension, no script */
List *options; /* List of DefElem nodes */
} CreateExtensionStmt;
***************
*** 1510,1515 **** typedef struct DropExtensionStmt
--- 1511,1522 ----
DropBehavior behavior; /* drop behavior - cascade/restrict */
} DropExtensionStmt;
+ typedef struct AlterExtensionStmt
+ {
+ NodeTag type;
+ char *extname;
+ } AlterExtensionStmt;
+
/* ----------------------
* Create/Drop Table Space Statements
* ----------------------
***************
*** 2114,2119 **** typedef struct AlterObjectSchemaStmt
--- 2121,2141 ----
} AlterObjectSchemaStmt;
/* ----------------------
+ * ALTER object SET EXTENSION Statement
+ * ----------------------
+ */
+ typedef struct AlterObjectExtensionStmt
+ {
+ NodeTag type;
+ ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */
+ RangeVar *relation; /* in case it's a table */
+ List *object; /* in case it's some other object */
+ List *objarg; /* argument types, if applicable */
+ char *addname; /* additional name if needed */
+ char *extname; /* the target extension */
+ } AlterObjectExtensionStmt;
+
+ /* ----------------------
* Alter Object Owner Statement
* ----------------------
*/
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 391,396 **** PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
--- 391,397 ----
PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("upgrade", UPGRADE, UNRESERVED_KEYWORD)
PG_KEYWORD("user", USER, RESERVED_KEYWORD)
PG_KEYWORD("using", USING, RESERVED_KEYWORD)
PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)