diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/index/amapi.c | 7 | ||||
-rw-r--r-- | src/backend/catalog/dependency.c | 9 | ||||
-rw-r--r-- | src/backend/catalog/objectaddress.c | 61 | ||||
-rw-r--r-- | src/backend/commands/Makefile | 2 | ||||
-rw-r--r-- | src/backend/commands/amcmds.c | 271 | ||||
-rw-r--r-- | src/backend/commands/event_trigger.c | 3 | ||||
-rw-r--r-- | src/backend/commands/opclasscmds.c | 42 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 15 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 13 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 25 | ||||
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 2 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 18 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 46 |
13 files changed, 430 insertions, 84 deletions
diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index bda166a9ef8..d347ebcba45 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -62,6 +62,13 @@ GetIndexAmRoutineByAmId(Oid amoid) amoid); amform = (Form_pg_am) GETSTRUCT(tuple); + /* Check if it's index access method */ + if (amform->amtype != AMTYPE_INDEX) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("access method \"%s\" is not of type %s", + NameStr(amform->amname), "INDEX"))); + amhandler = amform->amhandler; /* Complain if handler OID is invalid */ diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index c48e37bf9a2..17f9de1ff94 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -20,6 +20,7 @@ #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/objectaccess.h" +#include "catalog/pg_am.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" #include "catalog/pg_attrdef.h" @@ -141,6 +142,7 @@ static const Oid object_classes[] = { OperatorRelationId, /* OCLASS_OPERATOR */ OperatorClassRelationId, /* OCLASS_OPCLASS */ OperatorFamilyRelationId, /* OCLASS_OPFAMILY */ + AccessMethodRelationId, /* OCLASS_AM */ AccessMethodOperatorRelationId, /* OCLASS_AMOP */ AccessMethodProcedureRelationId, /* OCLASS_AMPROC */ RewriteRelationId, /* OCLASS_REWRITE */ @@ -1199,6 +1201,10 @@ doDeletion(const ObjectAddress *object, int flags) RemoveOpFamilyById(object->objectId); break; + case OCLASS_AM: + RemoveAccessMethodById(object->objectId); + break; + case OCLASS_AMOP: RemoveAmOpEntryById(object->objectId); break; @@ -2356,6 +2362,9 @@ getObjectClass(const ObjectAddress *object) case OperatorFamilyRelationId: return OCLASS_OPFAMILY; + case AccessMethodRelationId: + return OCLASS_AM; + case AccessMethodOperatorRelationId: return OCLASS_AMOP; diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index d2aaa6ded92..cb3ba853f4e 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -110,6 +110,18 @@ typedef struct static const ObjectPropertyType ObjectProperty[] = { { + AccessMethodRelationId, + AmOidIndexId, + AMOID, + AMNAME, + Anum_pg_am_amname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true + }, + { CastRelationId, CastOidIndexId, -1, @@ -561,6 +573,10 @@ static const struct object_type_map { "operator family", OBJECT_OPFAMILY }, + /* OCLASS_AM */ + { + "access method", OBJECT_ACCESS_METHOD + }, /* OCLASS_AMOP */ { "operator of access method", OBJECT_AMOP @@ -795,6 +811,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: case OBJECT_EVENT_TRIGGER: + case OBJECT_ACCESS_METHOD: address = get_object_address_unqualified(objtype, objname, missing_ok); break; @@ -1019,6 +1036,9 @@ get_object_address_unqualified(ObjectType objtype, switch (objtype) { + case OBJECT_ACCESS_METHOD: + msg = gettext_noop("access method name cannot be qualified"); + break; case OBJECT_DATABASE: msg = gettext_noop("database name cannot be qualified"); break; @@ -1061,6 +1081,11 @@ get_object_address_unqualified(ObjectType objtype, /* Translate name to OID. */ switch (objtype) { + case OBJECT_ACCESS_METHOD: + address.classId = AccessMethodRelationId; + address.objectId = get_am_oid(name, missing_ok); + address.objectSubId = 0; + break; case OBJECT_DATABASE: address.classId = DatabaseRelationId; address.objectId = get_database_oid(name, missing_ok); @@ -1489,7 +1514,7 @@ get_object_address_opcf(ObjectType objtype, List *objname, bool missing_ok) ObjectAddress address; /* XXX no missing_ok support here */ - amoid = get_am_oid(strVal(linitial(objname)), false); + amoid = get_index_am_oid(strVal(linitial(objname)), false); objname = list_copy_tail(objname, 1); switch (objtype) @@ -2179,6 +2204,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, break; case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: + case OBJECT_ACCESS_METHOD: /* We treat these object types as being owned by superusers */ if (!superuser_arg(roleid)) ereport(ERROR, @@ -3129,6 +3155,21 @@ getObjectDescription(const ObjectAddress *object) break; } + case OCLASS_AM: + { + HeapTuple tup; + + tup = SearchSysCache1(AMOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for access method %u", + object->objectId); + appendStringInfo(&buffer, _("access method %s"), + NameStr(((Form_pg_am) GETSTRUCT(tup))->amname)); + ReleaseSysCache(tup); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, @@ -3610,6 +3651,10 @@ getObjectTypeDescription(const ObjectAddress *object) appendStringInfoString(&buffer, "transform"); break; + case OCLASS_AM: + appendStringInfoString(&buffer, "access method"); + break; + default: appendStringInfo(&buffer, "unrecognized %u", object->classId); break; @@ -4566,6 +4611,20 @@ getObjectIdentityParts(const ObjectAddress *object, } break; + case OCLASS_AM: + { + char *amname; + + amname = get_am_name(object->objectId); + if (!amname) + elog(ERROR, "cache lookup failed for access method %u", + object->objectId); + appendStringInfoString(&buffer, quote_identifier(amname)); + if (objname) + *objname = list_make1(amname); + } + break; + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index b1ac704886f..6b3742c0a08 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -12,7 +12,7 @@ subdir = src/backend/commands top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \ +OBJS = amcmds.o aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \ collationcmds.o constraint.o conversioncmds.o copy.o createas.o \ dbcommands.o define.o discard.o dropcmds.o \ event_trigger.o explain.o extension.o foreigncmds.o functioncmds.o \ diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c new file mode 100644 index 00000000000..7a937543916 --- /dev/null +++ b/src/backend/commands/amcmds.c @@ -0,0 +1,271 @@ +/*------------------------------------------------------------------------- + * + * amcmds.c + * Routines for SQL commands that manipulate access methods. + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/commands/amcmds.c + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/heapam.h" +#include "access/htup_details.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_am.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "commands/defrem.h" +#include "miscadmin.h" +#include "parser/parse_func.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +static Oid lookup_index_am_handler_func(List *handler_name, char amtype); +static char *get_am_type_string(char amtype); + + +/* + * CreateAcessMethod + * Registers a new access method. + */ +ObjectAddress +CreateAccessMethod(CreateAmStmt *stmt) +{ + Relation rel; + ObjectAddress myself; + ObjectAddress referenced; + Oid amoid; + Oid amhandler; + bool nulls[Natts_pg_am]; + Datum values[Natts_pg_am]; + HeapTuple tup; + + rel = heap_open(AccessMethodRelationId, RowExclusiveLock); + + /* Must be super user */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create access method \"%s\"", + stmt->amname), + errhint("Must be superuser to create an access method."))); + + /* Check if name is used */ + amoid = GetSysCacheOid1(AMNAME, CStringGetDatum(stmt->amname)); + if (OidIsValid(amoid)) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("access method \"%s\" already exists", + stmt->amname))); + } + + /* + * Get the handler function oid, verifying the AM type while at it. + */ + amhandler = lookup_index_am_handler_func(stmt->handler_name, stmt->amtype); + + /* + * Insert tuple into pg_am. + */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_am_amname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->amname)); + values[Anum_pg_am_amhandler - 1] = ObjectIdGetDatum(amhandler); + values[Anum_pg_am_amtype - 1] = CharGetDatum(stmt->amtype); + + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + amoid = simple_heap_insert(rel, tup); + CatalogUpdateIndexes(rel, tup); + heap_freetuple(tup); + + myself.classId = AccessMethodRelationId; + myself.objectId = amoid; + myself.objectSubId = 0; + + /* Record dependency on handler function */ + referenced.classId = ProcedureRelationId; + referenced.objectId = amhandler; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + recordDependencyOnCurrentExtension(&myself, false); + + heap_close(rel, RowExclusiveLock); + + return myself; +} + +/* + * Guts of access method deletion. + */ +void +RemoveAccessMethodById(Oid amOid) +{ + Relation relation; + HeapTuple tup; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to drop access methods"))); + + relation = heap_open(AccessMethodRelationId, RowExclusiveLock); + + tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for access method %u", amOid); + + simple_heap_delete(relation, &tup->t_self); + + ReleaseSysCache(tup); + + heap_close(relation, RowExclusiveLock); +} + +/* + * get_am_type_oid + * Worker for various get_am_*_oid variants + * + * If missing_ok is false, throw an error if access method not found. If + * true, just return InvalidOid. + * + * If amtype is not '\0', an error is raised if the AM found is not of the + * given type. + */ +static Oid +get_am_type_oid(const char *amname, char amtype, bool missing_ok) +{ + HeapTuple tup; + Oid oid = InvalidOid; + + tup = SearchSysCache1(AMNAME, CStringGetDatum(amname)); + if (HeapTupleIsValid(tup)) + { + Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup); + + if (amtype != '\0' && + amform->amtype != amtype) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("access method \"%s\" is not of type %s", + NameStr(amform->amname), + get_am_type_string(amtype)))); + + oid = HeapTupleGetOid(tup); + ReleaseSysCache(tup); + } + + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("access method \"%s\" does not exist", amname))); + return oid; +} + +/* + * get_index_am_oid - given an access method name, look up its OID + * and verify it corresponds to an index AM. + */ +Oid +get_index_am_oid(const char *amname, bool missing_ok) +{ + return get_am_type_oid(amname, AMTYPE_INDEX, missing_ok); +} + +/* + * get_am_oid - given an access method name, look up its OID. + * The type is not checked. + */ +Oid +get_am_oid(const char *amname, bool missing_ok) +{ + return get_am_type_oid(amname, '\0', missing_ok); +} + +/* + * get_am_name - given an access method OID name and type, look up its name. + */ +char * +get_am_name(Oid amOid) +{ + HeapTuple tup; + char *result = NULL; + + tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid)); + if (HeapTupleIsValid(tup)) + { + Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup); + + result = pstrdup(NameStr(amform->amname)); + ReleaseSysCache(tup); + } + return result; +} + +/* + * Convert single charater access method type into string for error reporting. + */ +static char * +get_am_type_string(char amtype) +{ + switch (amtype) + { + case AMTYPE_INDEX: + return "INDEX"; + default: + /* shouldn't happen */ + elog(ERROR, "invalid access method type '%c'", amtype); + } +} + +/* + * Convert a handler function name to an Oid. If the return type of the + * function doesn't match the given AM type, an error is raised. + * + * This function either return valid function Oid or throw an error. + */ +static Oid +lookup_index_am_handler_func(List *handler_name, char amtype) +{ + Oid handlerOid; + static const Oid funcargtypes[1] = {INTERNALOID}; + + if (handler_name == NIL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("handler function is not specified"))); + + /* handlers have one argument of type internal */ + handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false); + + /* check that handler has the correct return type */ + switch (amtype) + { + case AMTYPE_INDEX: + if (get_func_rettype(handlerOid) != INDEX_AM_HANDLEROID) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function %s must return type \"%s\"", + NameListToString(handler_name), + "index_am_handler"))); + break; + default: + elog(ERROR, "unrecognized access method type \"%c\"", amtype); + } + + return handlerOid; +} diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 9e32f8d09b1..3f52ad836b4 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -86,6 +86,7 @@ typedef enum /* XXX merge this with ObjectTypeMap? */ static event_trigger_support_data event_trigger_support[] = { + {"ACCESS METHOD", true}, {"AGGREGATE", true}, {"CAST", true}, {"CONSTRAINT", true}, @@ -1078,6 +1079,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_EVENT_TRIGGER: /* no support for event triggers on event triggers */ return false; + case OBJECT_ACCESS_METHOD: case OBJECT_AGGREGATE: case OBJECT_AMOP: case OBJECT_AMPROC: @@ -1167,6 +1169,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_DEFACL: case OCLASS_EXTENSION: case OCLASS_POLICY: + case OCLASS_AM: return true; } diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 8a661968cd9..ac559fc9b41 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -678,6 +678,12 @@ DefineOpClass(CreateOpClassStmt *stmt) myself.objectId = opclassoid; myself.objectSubId = 0; + /* dependency on access method */ + referenced.classId = AccessMethodRelationId; + referenced.objectId = amoid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + /* dependency on namespace */ referenced.classId = NamespaceRelationId; referenced.objectId = namespaceoid; @@ -743,7 +749,7 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) get_namespace_name(namespaceoid)); /* Get access method OID, throwing an error if it doesn't exist. */ - amoid = get_am_oid(stmt->amname, false); + amoid = get_index_am_oid(stmt->amname, false); /* XXX Should we make any privilege check against the AM? */ @@ -1663,21 +1669,6 @@ RemoveAmProcEntryById(Oid entryOid) heap_close(rel, RowExclusiveLock); } -char * -get_am_name(Oid amOid) -{ - HeapTuple tup; - char *result = NULL; - - tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid)); - if (HeapTupleIsValid(tup)) - { - result = pstrdup(NameStr(((Form_pg_am) GETSTRUCT(tup))->amname)); - ReleaseSysCache(tup); - } - return result; -} - /* * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME * @@ -1723,22 +1714,3 @@ IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, get_am_name(opfmethod), get_namespace_name(opfnamespace)))); } - -/* - * get_am_oid - given an access method name, look up the OID - * - * If missing_ok is false, throw an error if access method not found. If - * true, just return InvalidOid. - */ -Oid -get_am_oid(const char *amname, bool missing_ok) -{ - Oid oid; - - oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname)); - if (!OidIsValid(oid) && !missing_ok) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("access method \"%s\" does not exist", amname))); - return oid; -} diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 6b5d1d6efce..6378db8bbea 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3831,6 +3831,18 @@ _copyCreateTransformStmt(const CreateTransformStmt *from) return newnode; } +static CreateAmStmt * +_copyCreateAmStmt(const CreateAmStmt *from) +{ + CreateAmStmt *newnode = makeNode(CreateAmStmt); + + COPY_STRING_FIELD(amname); + COPY_NODE_FIELD(handler_name); + COPY_SCALAR_FIELD(amtype); + + return newnode; +} + static CreateTrigStmt * _copyCreateTrigStmt(const CreateTrigStmt *from) { @@ -4822,6 +4834,9 @@ copyObject(const void *from) case T_CreateTransformStmt: retval = _copyCreateTransformStmt(from); break; + case T_CreateAmStmt: + retval = _copyCreateAmStmt(from); + break; case T_CreateTrigStmt: retval = _copyCreateTrigStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 87eb859e05e..854c062d32f 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1856,6 +1856,16 @@ _equalCreateTransformStmt(const CreateTransformStmt *a, const CreateTransformStm } static bool +_equalCreateAmStmt(const CreateAmStmt *a, const CreateAmStmt *b) +{ + COMPARE_STRING_FIELD(amname); + COMPARE_NODE_FIELD(handler_name); + COMPARE_SCALAR_FIELD(amtype); + + return true; +} + +static bool _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b) { COMPARE_STRING_FIELD(trigname); @@ -3147,6 +3157,9 @@ equal(const void *a, const void *b) case T_CreateTransformStmt: retval = _equalCreateTransformStmt(a, b); break; + case T_CreateAmStmt: + retval = _equalCreateAmStmt(a, b); + break; case T_CreateTrigStmt: retval = _equalCreateTrigStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a74fb772e14..12733528eb2 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -51,6 +51,7 @@ #include "catalog/index.h" #include "catalog/namespace.h" +#include "catalog/pg_am.h" #include "catalog/pg_trigger.h" #include "commands/defrem.h" #include "commands/trigger.h" @@ -263,7 +264,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DeallocateStmt PrepareStmt ExecuteStmt DropOwnedStmt ReassignOwnedStmt AlterTSConfigurationStmt AlterTSDictionaryStmt - CreateMatViewStmt RefreshMatViewStmt + CreateMatViewStmt RefreshMatViewStmt CreateAmStmt %type <node> select_no_parens select_with_parens select_clause simple_select values_clause @@ -604,7 +605,7 @@ 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 @@ -789,6 +790,7 @@ stmt : | CommentStmt | ConstraintsSetStmt | CopyStmt + | CreateAmStmt | CreateAsStmt | CreateAssertStmt | CreateCastStmt @@ -4708,6 +4710,23 @@ row_security_cmd: /***************************************************************************** * + * QUERY: + * CREATE ACCESS METHOD name HANDLER handler_name + * + *****************************************************************************/ + +CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name + { + CreateAmStmt *n = makeNode(CreateAmStmt); + n->amname = $4; + n->handler_name = $8; + n->amtype = AMTYPE_INDEX; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * * QUERIES : * CREATE TRIGGER ... * DROP TRIGGER ... @@ -5612,6 +5631,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; } | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } | INDEX { $$ = OBJECT_INDEX; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } + | ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; } | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } | COLLATION { $$ = OBJECT_COLLATION; } | CONVERSION_P { $$ = OBJECT_CONVERSION; } @@ -13778,6 +13798,7 @@ unreserved_keyword: | MATCH | MATERIALIZED | MAXVALUE + | METHOD | MINUTE_P | MINVALUE | MODE diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index dc431c7de0c..65284941ed9 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1709,7 +1709,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) * else dump and reload will produce a different index (breaking * pg_upgrade in particular). */ - if (index_rel->rd_rel->relam != get_am_oid(DEFAULT_INDEX_TYPE, false)) + if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("index \"%s\" is not a btree", index_name), diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 045f7f06ee2..4d0aac979fc 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1520,6 +1520,10 @@ ProcessUtilitySlow(Node *parsetree, address = ExecSecLabelStmt((SecLabelStmt *) parsetree); break; + case T_CreateAmStmt: + address = CreateAccessMethod((CreateAmStmt *) parsetree); + break; + default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(parsetree)); @@ -2160,6 +2164,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_TRANSFORM: tag = "DROP TRANSFORM"; break; + case OBJECT_ACCESS_METHOD: + tag = "DROP ACCESS METHOD"; + break; default: tag = "???"; } @@ -2256,6 +2263,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_COLLATION: tag = "CREATE COLLATION"; break; + case OBJECT_ACCESS_METHOD: + tag = "CREATE ACCESS METHOD"; + break; default: tag = "???"; } @@ -2519,6 +2529,10 @@ CreateCommandTag(Node *parsetree) tag = "ALTER POLICY"; break; + case T_CreateAmStmt: + tag = "CREATE ACCESS METHOD"; + break; + case T_PrepareStmt: tag = "PREPARE"; break; @@ -3076,6 +3090,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_CreateAmStmt: + lev = LOGSTMT_DDL; + break; + /* already-planned queries */ case T_PlannedStmt: { diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index d396ef142f9..b2c57e87a5e 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -6013,21 +6013,7 @@ string_to_bytea_const(const char *str, size_t str_len) *------------------------------------------------------------------------- */ -/* - * deconstruct_indexquals is a simple function to examine the indexquals - * attached to a proposed IndexPath. It returns a list of IndexQualInfo - * structs, one per qual expression. - */ -typedef struct -{ - RestrictInfo *rinfo; /* the indexqual itself */ - int indexcol; /* zero-based index column number */ - bool varonleft; /* true if index column is on left of qual */ - Oid clause_op; /* qual's operator OID, if relevant */ - Node *other_operand; /* non-index operand of qual's operator */ -} IndexQualInfo; - -static List * +List * deconstruct_indexquals(IndexPath *path) { List *result = NIL; @@ -6177,35 +6163,7 @@ orderby_operands_eval_cost(PlannerInfo *root, IndexPath *path) return qual_arg_cost; } -/* - * genericcostestimate is a general-purpose estimator that can be used for - * most index types. In some cases we use genericcostestimate as the base - * code and then incorporate additional index-type-specific knowledge in - * the type-specific calling function. To avoid code duplication, we make - * genericcostestimate return a number of intermediate values as well as - * its preliminary estimates of the output cost values. The GenericCosts - * struct includes all these values. - * - * Callers should initialize all fields of GenericCosts to zero. In addition, - * they can set numIndexTuples to some positive value if they have a better - * than default way of estimating the number of leaf index tuples visited. - */ -typedef struct -{ - /* These are the values the cost estimator must return to the planner */ - Cost indexStartupCost; /* index-related startup cost */ - Cost indexTotalCost; /* total index-related scan cost */ - Selectivity indexSelectivity; /* selectivity of index */ - double indexCorrelation; /* order correlation of index */ - - /* Intermediate values we obtain along the way */ - double numIndexPages; /* number of leaf pages visited */ - double numIndexTuples; /* number of leaf tuples visited */ - double spc_random_page_cost; /* relevant random_page_cost value */ - double num_sa_scans; /* # indexscans from ScalarArrayOps */ -} GenericCosts; - -static void +void genericcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, |