From d540f119373728d81ebdc9cb8563fc288e6a94d2 Mon Sep 17 00:00:00 2001 From: Petr Jelinek Date: Thu, 8 Jan 2015 23:26:39 +0100 Subject: [PATCH 2/3] seqam DDL WIP --- doc/src/sgml/ref/allfiles.sgml | 2 + doc/src/sgml/ref/create_seqam.sgml | 174 ++++++++++++++++++ doc/src/sgml/ref/drop_seqam.sgml | 87 +++++++++ doc/src/sgml/reference.sgml | 2 + src/backend/access/sequence/seqam.c | 329 +++++++++++++++++++++++++++++++++++ src/backend/catalog/dependency.c | 11 +- src/backend/catalog/objectaddress.c | 66 ++++++- src/backend/commands/dropcmds.c | 4 + src/backend/commands/event_trigger.c | 3 + src/backend/commands/sequence.c | 17 ++ src/backend/parser/gram.y | 14 +- src/backend/tcop/utility.c | 12 ++ src/include/access/seqam.h | 3 + src/include/catalog/dependency.h | 1 + src/include/catalog/pg_proc.h | 4 +- src/include/nodes/parsenodes.h | 1 + src/include/parser/kwlist.h | 1 + 17 files changed, 726 insertions(+), 5 deletions(-) create mode 100644 doc/src/sgml/ref/create_seqam.sgml create mode 100644 doc/src/sgml/ref/drop_seqam.sgml diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml index 7aa3128..2e4a250 100644 --- a/doc/src/sgml/ref/allfiles.sgml +++ b/doc/src/sgml/ref/allfiles.sgml @@ -74,6 +74,7 @@ Complete list of usable sgml source files in this directory. + @@ -116,6 +117,7 @@ Complete list of usable sgml source files in this directory. + diff --git a/doc/src/sgml/ref/create_seqam.sgml b/doc/src/sgml/ref/create_seqam.sgml new file mode 100644 index 0000000..7892820 --- /dev/null +++ b/doc/src/sgml/ref/create_seqam.sgml @@ -0,0 +1,174 @@ + + + + + CREATE ACCESS METHOD FOR SEQUENCES + + + + CREATE ACCESS METHOD FOR SEQUENCES + 7 + SQL - Language Statements + + + + CREATE ACCESS METHOD FOR SEQUENCES + define custom sequence access method + + + + +CREATE ACCESS METHOD FOR SEQUENCES name ( + EXTRACOLUMNS = _function , + RELOPTIONS = reloptions_function , + INIT = init_function , + ALLOC = alloc_function , + SETVAL = setval_function , + DUMP = dump_function, + RESTORE = restore_function +) + + + + + Description + + + CREATE ACCESS METHOD FOR SEQUENCES creates a sequence + access method. A sequence access method changes how values for SEQUENCEs + are generated. + + + + You must be a superuser to use CREATE ACCESS METHOD FOR SEQUENCES. + + + + + Parameters + + + + name + + + The name of the sequence access method to be created. This name must be + unique within the database. + + + + + + extracolumns_function + + + The name of the function that returns extra columns for the sequence + access method. + + + + + + reloptions_function + + + The name of the function for parsing reloptions for the sequence access + method. + + + + + + init_function + + + The name of the init function for the sequence access method. + + + + + + alloc_function + + + The name of the function which allocates new sequence id. + + + + + + setval_function + + + The name of the function which handles the setval + function call. + + + + + + dump_function + + + The name of the function used for dumping current state of the sequence + to a string. This function will be called by + pg_dump. + + + + + + restore_function + + + The name of the function used for restoring the state of the sequence + from a string. Calls to this function will be present in a database dumps + created by pg_dump. + + + + + + + + The function names can be schema-qualified if necessary. Argument types + are not given, since the argument list for each type of function is + predetermined. All functions are required. + + + + The arguments can appear in any order, not only the one shown above. + + + + + Examples + + + See the contrib/gapless_seq for example on how to write new + sequence access methods and how to use this command. + + + + + + Compatibility + + + There is no + CREATE ACCESS METHOD FOR SEQUENCES statement in the SQL + standard. + + + + + See Also + + + + + + diff --git a/doc/src/sgml/ref/drop_seqam.sgml b/doc/src/sgml/ref/drop_seqam.sgml new file mode 100644 index 0000000..959b777 --- /dev/null +++ b/doc/src/sgml/ref/drop_seqam.sgml @@ -0,0 +1,87 @@ + + + + + DROP ACCESS METHOD FOR SEQUENCES + + + + DROP ACCESS METHOD FOR SEQUENCES + 7 + SQL - Language Statements + + + + DROP ACCESS METHOD FOR SEQUENCES + remove a custom sequence access method + + + + +DROP ACCESS METHOD FOR SEQUENCES [ IF EXISTS ] name + + + + + Description + + + DROP ACCESS METHOD FOR SEQUENCES drop an existing + sequence access method. + + + + You must be a superuser to use the + DROP ACCESS METHOD FOR SEQUENCES. + + + + + Parameters + + + + + IF EXISTS + + + Do not throw an error if the sequence access method does not exist. + A notice is issued in this case. + + + + + + name + + + The name of an existing sequence access method to be removed. + + + + + + + + + + Compatibility + + + There is no + DDROP ACCESS METHOD FOR SEQUENCES statement in the SQL + standard. + + + + + See Also + + + + + + diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml index 10c9a6d..aeff87e 100644 --- a/doc/src/sgml/reference.sgml +++ b/doc/src/sgml/reference.sgml @@ -102,6 +102,7 @@ &createRole; &createRule; &createSchema; + &createSeqAM; &createSequence; &createServer; &createTable; @@ -144,6 +145,7 @@ &dropRole; &dropRule; &dropSchema; + &dropSeqAM; &dropSequence; &dropServer; &dropTable; diff --git a/src/backend/access/sequence/seqam.c b/src/backend/access/sequence/seqam.c index 053da0a..ae682ab 100644 --- a/src/backend/access/sequence/seqam.c +++ b/src/backend/access/sequence/seqam.c @@ -68,8 +68,19 @@ #include "access/relscan.h" #include "access/transam.h" #include "access/xact.h" +#include "catalog/dependency.h" +#include "catalog/objectaccess.h" +#include "catalog/objectaddress.h" +#include "catalog/indexing.h" +#include "catalog/pg_proc.h" #include "catalog/pg_seqam.h" +#include "catalog/pg_type.h" +#include "commands/defrem.h" +#include "miscadmin.h" +#include "parser/parse_func.h" +#include "utils/builtins.h" #include "utils/guc.h" +#include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -392,6 +403,324 @@ GetDefaultSeqAM(void) return get_seqam_oid(default_seqam, false); } + +/* + * Find seqam function by name and validate it. + */ +static Datum +get_seqam_func(DefElem *defel, int attnum) +{ + List *funcName = defGetQualifiedName(defel); + Oid typeId[6]; + Oid retTypeId; + int nargs; + Oid procOid; + + typeId[0] = INTERNALOID; + + switch (attnum) + { + case Anum_pg_seqam_amextracols: + /* + * This function returns internal type so it has to also accept + * internal on input even though there is actually no parameter + * sent. + */ + nargs = 1; + retTypeId = INTERNALOID; + break; + + case Anum_pg_seqam_amreloptions: + nargs = 2; + typeId[1] = BOOLOID; + retTypeId = BYTEAOID; + break; + + case Anum_pg_seqam_aminit: + nargs = 5; + typeId[1] = INTERNALOID; + typeId[2] = BOOLOID; + typeId[3] = INTERNALOID; + typeId[4] = INTERNALOID; + retTypeId = VOIDOID; + break; + + case Anum_pg_seqam_amalloc: + nargs = 4; + typeId[1] = INTERNALOID; + typeId[2] = INT8OID; + typeId[3] = INTERNALOID; + retTypeId = INT8OID; + break; + + case Anum_pg_seqam_amsetval: + nargs = 3; + typeId[1] = INTERNALOID; + typeId[2] = INT8OID; + retTypeId = VOIDOID; + break; + + case Anum_pg_seqam_amdump: + nargs = 2; + typeId[1] = INTERNALOID; + retTypeId = CSTRINGOID; + break; + + case Anum_pg_seqam_amrestore: + nargs = 3; + typeId[1] = INTERNALOID; + typeId[2] = CSTRINGOID; + retTypeId = VOIDOID; + break; + + default: + /* should not be here */ + elog(ERROR, "unrecognized attribute for sequence access method: %d", + attnum); + nargs = 0; /* keep compiler quiet */ + } + + procOid = LookupFuncName(funcName, nargs, typeId, false); + if (get_func_rettype(procOid) != retTypeId) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("function %s should return type %s", + func_signature_string(funcName, nargs, NIL, typeId), + format_type_be(retTypeId)))); + + return ObjectIdGetDatum(procOid); +} + +/* + * make pg_depend entries for a new pg_seqam entry + */ +static void +makeSeqAMDependencies(HeapTuple tuple) +{ + Form_pg_seqam seqam = (Form_pg_seqam) GETSTRUCT(tuple); + ObjectAddress myself, + referenced; + + myself.classId = SeqAccessMethodRelationId; + myself.objectId = HeapTupleGetOid(tuple); + myself.objectSubId = 0; + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + /* dependencies on functions */ + referenced.classId = ProcedureRelationId; + referenced.objectSubId = 0; + + referenced.objectId = seqam->seqamextracols; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.objectId = seqam->seqamreloptions; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.objectId = seqam->seqaminit; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.objectId = seqam->seqamalloc; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.objectId = seqam->seqamsetval; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.objectId = seqam->seqamdump; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.objectId = seqam->seqamrestore; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); +} + +/* + * Create a sequence access method record in pg_seqam catalog. + * + * Only superusers can create a sequence access methods. + */ +Oid +DefineSeqAM(List *names, List *parameters) +{ + char *seqamname = strVal(linitial(names)); + Oid seqamoid; + ListCell *pl; + Relation rel; + Datum values[Natts_pg_seqam]; + bool nulls[Natts_pg_seqam]; + HeapTuple tuple; + + /* Must be super user. */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create sequence access method \"%s\"", + seqamname), + errhint("Must be superuser to create a sequence access method."))); + + /* Must not already exist. */ + seqamoid = get_seqam_oid(seqamname, true); + if (OidIsValid(seqamoid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("sequence access method \"%s\" already exists", + seqamname))); + + /* Initialize the values. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_seqam_amname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(seqamname)); + + /* + * loop over the definition list and extract the information we need. + */ + foreach(pl, parameters) + { + DefElem *defel = (DefElem *) lfirst(pl); + + if (pg_strcasecmp(defel->defname, "extracolumns") == 0) + { + values[Anum_pg_seqam_amextracols - 1] = + get_seqam_func(defel, Anum_pg_seqam_amextracols); + } + else if (pg_strcasecmp(defel->defname, "reloptions") == 0) + { + values[Anum_pg_seqam_amreloptions - 1] = + get_seqam_func(defel, Anum_pg_seqam_amreloptions); + } + else if (pg_strcasecmp(defel->defname, "init") == 0) + { + values[Anum_pg_seqam_aminit - 1] = + get_seqam_func(defel, Anum_pg_seqam_aminit); + } + else if (pg_strcasecmp(defel->defname, "alloc") == 0) + { + values[Anum_pg_seqam_amalloc - 1] = + get_seqam_func(defel, Anum_pg_seqam_amalloc); + } + else if (pg_strcasecmp(defel->defname, "setval") == 0) + { + values[Anum_pg_seqam_amsetval - 1] = + get_seqam_func(defel, Anum_pg_seqam_amsetval); + } + else if (pg_strcasecmp(defel->defname, "dump") == 0) + { + values[Anum_pg_seqam_amdump - 1] = + get_seqam_func(defel, Anum_pg_seqam_amdump); + } + else if (pg_strcasecmp(defel->defname, "restore") == 0) + { + values[Anum_pg_seqam_amrestore - 1] = + get_seqam_func(defel, Anum_pg_seqam_amrestore); + } + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("sequence access method parameter \"%s\" not recognized", + defel->defname))); + } + + /* + * Validation. + */ + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amextracols - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method extracolumns function is required"))); + + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amreloptions - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method reloptions function is required"))); + + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_aminit - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method init function is required"))); + + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amalloc - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method alloc function is required"))); + + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amsetval - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method setval function is required"))); + + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amdump - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method dump function is required"))); + + if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amrestore - 1]))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("sequence access method restore function is required"))); + + /* + * Insert tuple into pg_seqam. + */ + rel = heap_open(SeqAccessMethodRelationId, RowExclusiveLock); + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + + seqamoid = simple_heap_insert(rel, tuple); + + CatalogUpdateIndexes(rel, tuple); + + makeSeqAMDependencies(tuple); + + heap_freetuple(tuple); + + /* Post creation hook */ + InvokeObjectPostCreateHook(SeqAccessMethodRelationId, seqamoid, 0); + + heap_close(rel, RowExclusiveLock); + + return seqamoid; +} + +/* + * Drop a sequence access method. + */ +void +RemoveSeqAMById(Oid seqamoid) +{ + Relation rel; + HeapTuple tuple; + Form_pg_seqam seqam; + + /* + * Find the target tuple + */ + rel = heap_open(SeqAccessMethodRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(SEQAMOID, ObjectIdGetDatum(seqamoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for sequence access method %u", + seqamoid); + + seqam = (Form_pg_seqam) GETSTRUCT(tuple); + /* Can't drop builtin local sequence access method. */ + if (seqamoid == LOCAL_SEQAM_OID) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for sequence access method %s", + NameStr(seqam->seqamname)))); + + /* + * Remove the pg_seqam tuple (this will roll back if we fail below) + */ + simple_heap_delete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + + heap_close(rel, RowExclusiveLock); +} + /* * get_seqam_oid - given a sequence AM name, look up the OID * diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index bacb242..9340798 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -16,6 +16,7 @@ #include "access/htup_details.h" #include "access/xact.h" +#include "access/seqam.h" #include "catalog/dependency.h" #include "catalog/heap.h" #include "catalog/index.h" @@ -157,7 +158,8 @@ static const Oid object_classes[MAX_OCLASS] = { DefaultAclRelationId, /* OCLASS_DEFACL */ ExtensionRelationId, /* OCLASS_EXTENSION */ EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */ - PolicyRelationId /* OCLASS_POLICY */ + PolicyRelationId, /* OCLASS_POLICY */ + SeqAccessMethodRelationId /* OCLASS_SEQAM */ }; @@ -1265,6 +1267,10 @@ doDeletion(const ObjectAddress *object, int flags) RemovePolicyById(object->objectId); break; + case OCLASS_SEQAM: + RemoveSeqAMById(object->objectId); + break; + default: elog(ERROR, "unrecognized object class: %u", object->classId); @@ -2373,6 +2379,9 @@ getObjectClass(const ObjectAddress *object) case PolicyRelationId: return OCLASS_POLICY; + + case SeqAccessMethodRelationId: + return OCLASS_SEQAM; } /* shouldn't get here */ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 2412a24..58cf813 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -430,6 +430,18 @@ static const ObjectPropertyType ObjectProperty[] = Anum_pg_type_typacl, ACL_KIND_TYPE, true + }, + { + SeqAccessMethodRelationId, + SeqAmOidIndexId, + SEQAMOID, + SEQAMNAME, + Anum_pg_seqam_amname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true } }; @@ -529,7 +541,9 @@ ObjectTypeMap[] = /* OCLASS_EVENT_TRIGGER */ { "event trigger", OBJECT_EVENT_TRIGGER }, /* OCLASS_POLICY */ - { "policy", OBJECT_POLICY } + { "policy", OBJECT_POLICY }, + /* OCLASS_SEQAM */ + { "sequence access method", OBJECT_SEQAM } }; @@ -671,6 +685,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: case OBJECT_EVENT_TRIGGER: + case OBJECT_SEQAM: address = get_object_address_unqualified(objtype, objname, missing_ok); break; @@ -897,6 +912,9 @@ get_object_address_unqualified(ObjectType objtype, case OBJECT_EVENT_TRIGGER: msg = gettext_noop("event trigger name cannot be qualified"); break; + case OBJECT_SEQAM: + msg = gettext_noop("sequence access method name cannot be qualified"); + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); msg = NULL; /* placate compiler */ @@ -957,6 +975,11 @@ get_object_address_unqualified(ObjectType objtype, address.objectId = get_event_trigger_oid(name, missing_ok); address.objectSubId = 0; break; + case OBJECT_SEQAM: + address.classId = SeqAccessMethodRelationId; + address.objectId = get_seqam_oid(name, missing_ok); + address.objectSubId = 0; + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, which doesn't know elog won't return */ @@ -1721,6 +1744,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, break; case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: + case OBJECT_SEQAM: /* We treat these object types as being owned by superusers */ if (!superuser_arg(roleid)) ereport(ERROR, @@ -2655,6 +2679,21 @@ getObjectDescription(const ObjectAddress *object) break; } + case OCLASS_SEQAM: + { + HeapTuple tup; + + tup = SearchSysCache1(SEQAMOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for sequence access method %u", + object->objectId); + appendStringInfo(&buffer, _("sequence access method %s"), + NameStr(((Form_pg_seqam) GETSTRUCT(tup))->seqamname)); + ReleaseSysCache(tup); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, @@ -3132,6 +3171,10 @@ getObjectTypeDescription(const ObjectAddress *object) appendStringInfoString(&buffer, "policy"); break; + case OCLASS_SEQAM: + appendStringInfoString(&buffer, "sequence access method"); + break; + default: appendStringInfo(&buffer, "unrecognized %u", object->classId); break; @@ -4026,6 +4069,27 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case OCLASS_SEQAM: + { + char *seqamname; + HeapTuple tup; + Form_pg_seqam seqamForm; + + tup = SearchSysCache1(SEQAMOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for sequence access method %u", + object->objectId); + seqamForm = (Form_pg_seqam) GETSTRUCT(tup); + seqamname = pstrdup(NameStr(seqamForm->seqamname)); + ReleaseSysCache(tup); + appendStringInfoString(&buffer, + quote_identifier(seqamname)); + if (objname) + *objname = list_make1(seqamname); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index e5185ba..01d772a 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -421,6 +421,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) args = strVal(linitial(objargs)); } break; + case OBJECT_SEQAM: + msg = gettext_noop("sequence access method \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; default: elog(ERROR, "unexpected object type (%d)", (int) objtype); break; diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index a33a5ad..0c4d63e 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -72,6 +72,7 @@ typedef enum } event_trigger_command_tag_check_result; static event_trigger_support_data event_trigger_support[] = { + {"ACCESS METHOD FOR SEQUENCES", true}, {"AGGREGATE", true}, {"CAST", true}, {"CONSTRAINT", true}, @@ -1075,6 +1076,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_POLICY: case OBJECT_RULE: case OBJECT_SCHEMA: + case OBJECT_SEQAM: case OBJECT_SEQUENCE: case OBJECT_TABCONSTRAINT: case OBJECT_TABLE: @@ -1134,6 +1136,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_DEFACL: case OCLASS_EXTENSION: case OCLASS_POLICY: + case OCLASS_SEQAM: return true; case MAX_OCLASS: diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 5834b2d..fdf8465 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1530,9 +1530,26 @@ seqrel_update_relam(Oid seqoid, Oid seqamid) if (pgcform->relam != seqamid) { + ObjectAddress myself, + referenced; + pgcform->relam = seqamid; simple_heap_update(rd, &ctup->t_self, ctup); CatalogUpdateIndexes(rd, ctup); + + /* Remove dependency on previous SeqAM */ + deleteDependencyRecordsForClass(RelationRelationId, seqoid, + SeqAccessMethodRelationId, + DEPENDENCY_NORMAL); + + /* Record dependency on new SeqAM */ + myself.classId = RelationRelationId; + myself.objectId = seqoid; + myself.objectSubId = 0; + referenced.classId = SeqAccessMethodRelationId; + referenced.objectId = seqamid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } heap_freetuple(ctup); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 976eb6b..fa37899 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -586,7 +586,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED - MAPPING MATCH MATERIALIZED MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE + MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P + MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NONE NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF @@ -5167,6 +5168,15 @@ DefineStmt: n->definition = list_make1(makeDefElem("from", (Node *) $5)); $$ = (Node *)n; } + | CREATE ACCESS METHOD FOR SEQUENCES name definition + { + DefineStmt *n = makeNode(DefineStmt); + n->kind = OBJECT_SEQAM; + n->args = NIL; + n->defnames = list_make1(makeString($6)); + n->definition = $7; + $$ = (Node *)n; + } ; definition: '(' def_list ')' { $$ = $2; } @@ -5625,6 +5635,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; } | TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; } | TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; } | TEXT_P SEARCH CONFIGURATION { $$ = OBJECT_TSCONFIGURATION; } + | ACCESS METHOD FOR SEQUENCES { $$ = OBJECT_SEQAM; } ; any_name_list: @@ -13356,6 +13367,7 @@ unreserved_keyword: | MATCH | MATERIALIZED | MAXVALUE + | METHOD | MINUTE_P | MINVALUE | MODE diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 3533cfa..c8e1876 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -18,6 +18,7 @@ #include "access/htup_details.h" #include "access/reloptions.h" +#include "access/seqam.h" #include "access/twophase.h" #include "access/xact.h" #include "access/xlog.h" @@ -1106,6 +1107,11 @@ ProcessUtilitySlow(Node *parsetree, Assert(stmt->args == NIL); DefineCollation(stmt->defnames, stmt->definition); break; + case OBJECT_SEQAM: + Assert(stmt->args == NIL); + Assert(list_length(stmt->defnames) == 1); + DefineSeqAM(stmt->defnames, stmt->definition); + break; default: elog(ERROR, "unrecognized define stmt type: %d", (int) stmt->kind); @@ -1960,6 +1966,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_POLICY: tag = "DROP POLICY"; break; + case OBJECT_SEQAM: + tag = "DROP ACCESS METHOD FOR SEQUENCES"; + break; default: tag = "???"; } @@ -2056,6 +2065,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_COLLATION: tag = "CREATE COLLATION"; break; + case OBJECT_SEQAM: + tag = "CREATE ACCESS METHOD FOR SEQUENCES"; + break; default: tag = "???"; } diff --git a/src/include/access/seqam.h b/src/include/access/seqam.h index c4f6f73..b8b3b27 100644 --- a/src/include/access/seqam.h +++ b/src/include/access/seqam.h @@ -40,6 +40,9 @@ extern char *default_seqam; extern Oid GetDefaultSeqAM(void); +extern Oid DefineSeqAM(List *names, List *parameters); +extern void RemoveSeqAMById(Oid seqamoid); + extern List *seqam_extra_columns(Oid seqamid); extern void seqam_init(Oid seqamid, List *seqparams, List *reloptions, bool is_init, diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 6481ac8..9485d02 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -148,6 +148,7 @@ typedef enum ObjectClass OCLASS_EXTENSION, /* pg_extension */ OCLASS_EVENT_TRIGGER, /* pg_event_trigger */ OCLASS_POLICY, /* pg_policy */ + OCLASS_SEQAM, /* pg_seqam */ MAX_OCLASS /* MUST BE LAST */ } ObjectClass; diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 0b6e148..517035f 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -1817,9 +1817,9 @@ DATA(insert OID = 1576 ( setval PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 20 " DESCR("set sequence value"); DATA(insert OID = 3078 ( pg_sequence_parameters PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2249 "26" "{26,20,20,20,20,16}" "{i,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option}" _null_ pg_sequence_parameters _null_ _null_ _null_)); DESCR("sequence parameters, for use by information schema"); -DATA(insert OID = 3261 ( pg_sequence_dump_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2275 "2205" _null_ _null_ _null_ _null_ pg_sequence_dump_state _null_ _null_ _null_ )); +DATA(insert OID = 3277 ( pg_sequence_dump_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2275 "2205" _null_ _null_ _null_ _null_ pg_sequence_dump_state _null_ _null_ _null_ )); DESCR("Dump state of a sequence"); -DATA(insert OID = 3262 ( pg_sequence_restore_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 2278 "2205 2275" _null_ _null_ _null_ _null_ pg_sequence_restore_state _null_ _null_ _null_ )); +DATA(insert OID = 3278 ( pg_sequence_restore_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 2278 "2205 2275" _null_ _null_ _null_ _null_ pg_sequence_restore_state _null_ _null_ _null_ )); DESCR("Restore state of a sequence"); DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ )); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2dd2f71..a9580e8 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1231,6 +1231,7 @@ typedef enum ObjectType OBJECT_ROLE, OBJECT_RULE, OBJECT_SCHEMA, + OBJECT_SEQAM, OBJECT_SEQUENCE, OBJECT_TABCONSTRAINT, OBJECT_TABLE, diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 7c243ec..ece52b0 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -236,6 +236,7 @@ PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD) PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD) PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD) PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD) +PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD) PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD) PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD) PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD) -- 1.9.1