0001-create-am-infra-2015-03-05.patch
application/x-patch
Filename: 0001-create-am-infra-2015-03-05.patch
Type: application/x-patch
Part: 0
Message:
Re: Sequence Access Method WIP
Patch
Format: format-patch
Series: patch 0001
Subject: create-am-infra
| File | + | − |
|---|---|---|
| src/backend/access/index/amapi.c | 7 | 0 |
| src/backend/catalog/dependency.c | 9 | 1 |
| src/backend/catalog/objectaddress.c | 112 | 1 |
| src/backend/commands/amcmds.c | 272 | 0 |
| src/backend/commands/event_trigger.c | 3 | 0 |
| src/backend/commands/Makefile | 1 | 1 |
| src/backend/commands/opclasscmds.c | 7 | 35 |
| src/backend/nodes/copyfuncs.c | 15 | 0 |
| src/backend/nodes/equalfuncs.c | 13 | 0 |
| src/backend/parser/parse_utilcmd.c | 2 | 1 |
| src/backend/tcop/utility.c | 18 | 0 |
| src/bin/pg_dump/common.c | 5 | 0 |
| src/bin/pg_dump/pg_dump.c | 134 | 0 |
| src/bin/pg_dump/pg_dump.h | 8 | 0 |
| src/bin/pg_dump/pg_dump_sort.c | 6 | 0 |
| src/include/catalog/dependency.h | 3 | 2 |
| src/include/catalog/pg_am.h | 17 | 7 |
| src/include/commands/defrem.h | 6 | 2 |
| src/include/nodes/nodes.h | 1 | 0 |
| src/include/nodes/parsenodes.h | 13 | 0 |
From 84e10721a343d229da415891e8f263ad832d4c66 Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmodos@pjmodos.net>
Date: Wed, 2 Mar 2016 15:32:02 +0100
Subject: [PATCH 1/3] create-am-infra
---
src/backend/access/index/amapi.c | 7 +
src/backend/catalog/dependency.c | 10 +-
src/backend/catalog/objectaddress.c | 113 ++++++++++++++-
src/backend/commands/Makefile | 2 +-
src/backend/commands/amcmds.c | 272 +++++++++++++++++++++++++++++++++++
src/backend/commands/event_trigger.c | 3 +
src/backend/commands/opclasscmds.c | 42 +-----
src/backend/nodes/copyfuncs.c | 15 ++
src/backend/nodes/equalfuncs.c | 13 ++
src/backend/parser/parse_utilcmd.c | 3 +-
src/backend/tcop/utility.c | 18 +++
src/bin/pg_dump/common.c | 5 +
src/bin/pg_dump/pg_dump.c | 134 +++++++++++++++++
src/bin/pg_dump/pg_dump.h | 8 ++
src/bin/pg_dump/pg_dump_sort.c | 6 +
src/include/catalog/dependency.h | 5 +-
src/include/catalog/pg_am.h | 24 +++-
src/include/commands/defrem.h | 8 +-
src/include/nodes/nodes.h | 1 +
src/include/nodes/parsenodes.h | 13 ++
20 files changed, 652 insertions(+), 50 deletions(-)
create mode 100644 src/backend/commands/amcmds.c
diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c
index bda166a..e9b9b3f 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\" type is not index",
+ NameStr(amform->amname))));
+
amhandler = amform->amhandler;
/* Complain if handler OID is invalid */
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index c48e37b..a86a488 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"
@@ -160,7 +161,8 @@ static const Oid object_classes[] = {
ExtensionRelationId, /* OCLASS_EXTENSION */
EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */
PolicyRelationId, /* OCLASS_POLICY */
- TransformRelationId /* OCLASS_TRANSFORM */
+ TransformRelationId, /* OCLASS_TRANSFORM */
+ AccessMethodRelationId /* OCLASS_AM */
};
@@ -1270,6 +1272,9 @@ doDeletion(const ObjectAddress *object, int flags)
case OCLASS_TRANSFORM:
DropTransformById(object->objectId);
+
+ case OCLASS_AM:
+ RemoveAccessMethodById(object->objectId);
break;
default:
@@ -2415,6 +2420,9 @@ getObjectClass(const ObjectAddress *object)
case TransformRelationId:
return OCLASS_TRANSFORM;
+
+ case AccessMethodRelationId:
+ return OCLASS_AM;
}
/* shouldn't get here */
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index d2aaa6d..2506344 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -438,6 +438,18 @@ static const ObjectPropertyType ObjectProperty[] =
Anum_pg_type_typacl,
ACL_KIND_TYPE,
true
+ },
+ {
+ AccessMethodRelationId,
+ AmOidIndexId,
+ AMOID,
+ AMNAME,
+ Anum_pg_am_amname,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
+ -1,
+ true
}
};
@@ -640,6 +652,10 @@ static const struct object_type_map
/* OCLASS_TRANSFORM */
{
"transform", OBJECT_TRANSFORM
+ },
+ /* OCLASS_AM */
+ {
+ "access method", OBJECT_ACCESS_METHOD,
}
};
@@ -674,6 +690,8 @@ static ObjectAddress get_object_address_usermapping(List *objname,
List *objargs, bool missing_ok);
static ObjectAddress get_object_address_defacl(List *objname, List *objargs,
bool missing_ok);
+static ObjectAddress get_object_address_am(ObjectType objtype, List *objname,
+ bool missing_ok);
static const ObjectPropertyType *get_object_property_data(Oid class_id);
static void getRelationDescription(StringInfo buffer, Oid relid);
@@ -913,6 +931,9 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
address = get_object_address_defacl(objname, objargs,
missing_ok);
break;
+ case OBJECT_ACCESS_METHOD:
+ address = get_object_address_am(objtype, objname, missing_ok);
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
/* placate compiler, in case it thinks elog might return */
@@ -1489,7 +1510,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_am_oid(strVal(linitial(objname)), AMTYPE_INDEX, false);
objname = list_copy_tail(objname, 1);
switch (objtype)
@@ -1516,6 +1537,65 @@ get_object_address_opcf(ObjectType objtype, List *objname, bool missing_ok)
}
/*
+ * Find the ObjectAddress for an access method.
+ */
+static ObjectAddress
+get_object_address_am(ObjectType objtype, List *objname, bool missing_ok)
+{
+ ObjectAddress address;
+ char *amname, *catalogname;
+ Type tup;
+
+ switch (list_length(objname))
+ {
+ case 1:
+ amname = strVal(linitial(objname));
+ break;
+ case 2:
+ catalogname = strVal(linitial(objname));
+ amname = strVal(lsecond(objname));
+
+ /*
+ * We check the catalog name and then ignore it.
+ */
+ if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cross-database references are not implemented: %s",
+ NameListToString(objname))));
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("improper access method name (too many dotted names): %s",
+ NameListToString(objname))));
+ break;
+ }
+
+ address.classId = AccessMethodRelationId;
+ address.objectId = InvalidOid;
+ address.objectSubId = 0;
+
+ tup = SearchSysCache1(AMNAME, PointerGetDatum(amname));
+ if (!HeapTupleIsValid(tup))
+ {
+ /* Access method is missing, report error if needed */
+ if (!missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ amname)));
+ return address;
+ }
+
+ /* Access method is found, return its oid */
+ address.objectId = HeapTupleGetOid(tup);
+ ReleaseSysCache(tup);
+
+ return address;
+}
+
+/*
* Find the ObjectAddress for an opclass/opfamily member.
*
* (The returned address corresponds to a pg_amop/pg_amproc object).
@@ -2179,6 +2259,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 +3210,18 @@ getObjectDescription(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);
+ appendStringInfo(&buffer, _("access method %s"), amname);
+ break;
+ }
+
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
@@ -3610,6 +3703,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 +4663,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 b1ac704..6b3742c 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 0000000..c79cbb1
--- /dev/null
+++ b/src/backend/commands/amcmds.c
@@ -0,0 +1,272 @@
+/*-------------------------------------------------------------------------
+ *
+ * amcmds.c
+ * Routines for SQL commands that manipulate access methods.
+ *
+ * Portions Copyright (c) 1996-2014, 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/genam.h"
+#include "access/heapam.h"
+#include "access/htup_details.h"
+#include "access/xact.h"
+#include "catalog/binary_upgrade.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/heap.h"
+#include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_authid.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_collation.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_depend.h"
+#include "catalog/pg_enum.h"
+#include "catalog/pg_language.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_proc_fn.h"
+#include "catalog/pg_range.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_type_fn.h"
+#include "commands/dbcommands.h"
+#include "commands/defrem.h"
+#include "commands/tablecmds.h"
+#include "commands/typecmds.h"
+#include "executor/executor.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "optimizer/planner.h"
+#include "optimizer/var.h"
+#include "parser/parse_coerce.h"
+#include "parser/parse_collate.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_func.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+#include "utils/snapmgr.h"
+#include "utils/syscache.h"
+#include "utils/tqual.h"
+
+/*
+ * Convert a handler function name passed from the parser to an Oid. This
+ * function either return valid function Oid or throw an error.
+ */
+static Oid
+lookup_am_handler_func(List *handler_name, Oid handler_type)
+{
+ Oid handlerOid;
+ Oid funcargtypes[1] = {INTERNALOID};
+
+ if (handler_name == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("handler function is not specified")));
+
+ /* handlers have no arguments */
+ handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false);
+
+ /* check that handler has correct return type */
+ if (get_func_rettype(handlerOid) != handler_type)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s must return type \"%s\"",
+ NameListToString(handler_name),
+ format_type_be(handler_type))));
+
+ return handlerOid;
+}
+
+/*
+ * 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 access method.")));
+
+ /* Check if name is busy */
+ amoid = GetSysCacheOid1(AMNAME, CStringGetDatum(stmt->amname));
+ if (OidIsValid(amoid))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("access method \"%s\" already exists", stmt->amname)));
+ }
+
+ /*
+ * Get handler function oid. Handler signature depends on access method
+ * type.
+ */
+ switch(stmt->amtype)
+ {
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("invalid access method type \"%c\"", stmt->amtype)));
+ break;
+ }
+
+ /*
+ * 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 dependecy 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);
+}
+
+/*
+ * Convert single charater access method type into string for error reporting.
+ */
+static char *
+get_am_type_string(char amtype)
+{
+ switch (amtype)
+ {
+ default:
+ elog(ERROR, "invalid access method type \"%c\"", amtype);
+ }
+}
+
+/*
+ * get_am_oid - given an access method name and type, 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, 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 (amform->amtype != amtype)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("access method \"%s\" type is not %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_am_name - given an access method OID name and type, look up the name
+ *
+ * Access method type is not required for lookup. However it's useful to check
+ * the type to ensure it is what we're looking for.
+ */
+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;
+}
+
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 9e32f8d..3f52ad8 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 8a66196..19dac98 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_am_oid(stmt->amname, AMTYPE_INDEX, 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 a9e9cc3..85bd5ac 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3828,6 +3828,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)
{
@@ -4819,6 +4831,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 b9c3959..f19fde1 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1855,6 +1855,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);
@@ -3146,6 +3156,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/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index dc431c7..8ae5400 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1709,7 +1709,8 @@ 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_am_oid(DEFAULT_INDEX_TYPE,
+ AMTYPE_INDEX, 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 045f7f0..4d0aac9 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/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index f798b15..1acd91a 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -98,6 +98,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
int numProcLangs;
int numCasts;
int numTransforms;
+ int numAccessMethods;
int numOpclasses;
int numOpfamilies;
int numConversions;
@@ -169,6 +170,10 @@ getSchemaData(Archive *fout, int *numTablesPtr)
oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
if (g_verbose)
+ write_msg(NULL, "reading user-defined access methods\n");
+ getAccessMethods(fout, &numAccessMethods);
+
+ if (g_verbose)
write_msg(NULL, "reading user-defined operator classes\n");
getOpclasses(fout, &numOpclasses);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 64c2673..8999bcc 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -173,6 +173,7 @@ static void dumpFunc(Archive *fout, FuncInfo *finfo);
static void dumpCast(Archive *fout, CastInfo *cast);
static void dumpTransform(Archive *fout, TransformInfo *transform);
static void dumpOpr(Archive *fout, OprInfo *oprinfo);
+static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
static void dumpCollation(Archive *fout, CollInfo *convinfo);
@@ -4101,6 +4102,82 @@ getConversions(Archive *fout, int *numConversions)
}
/*
+ * getAccessMethods:
+ * read all user-defined access methods in the system catalogs and return
+ * them in the AccessMethodInfo* structure
+ *
+ * numAccessMethods is set to the number of access methods read in
+ */
+AccessMethodInfo *
+getAccessMethods(Archive *fout, int *numAccessMethods)
+{
+ DumpOptions *dopt = fout->dopt;
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query;
+ AccessMethodInfo *aminfo;
+ int i_tableoid;
+ int i_oid;
+ int i_amname;
+ int i_amhandler;
+
+ /* Before 9.6, there are no user-defined access methods */
+ if (fout->remoteVersion < 90600)
+ {
+ *numAccessMethods = 0;
+ return NULL;
+ }
+
+ query = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(fout, "pg_catalog");
+
+ /*
+ * Select only user-defined access methods assuming all built-in access
+ * methods have oid < 10000.
+ */
+ appendPQExpBuffer(query, "SELECT tableoid, oid, amname, "
+ "amhandler::pg_catalog.regproc AS amhandler "
+ "FROM pg_am "
+ "WHERE oid >= 10000");
+
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numAccessMethods = ntups;
+
+ aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_amname = PQfnumber(res, "amname");
+ i_amhandler = PQfnumber(res, "amhandler");
+
+ for (i = 0; i < ntups; i++)
+ {
+ aminfo[i].dobj.objType = DO_ACCESS_METHOD;
+ aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&aminfo[i].dobj);
+ aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
+ aminfo[i].dobj.namespace = NULL;
+ aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(aminfo[i].dobj), dopt);
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return aminfo;
+}
+
+
+/*
* getOpclasses:
* read all opclasses in the system catalogs and return them in the
* OpclassInfo* structure
@@ -8408,6 +8485,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_OPERATOR:
dumpOpr(fout, (OprInfo *) dobj);
break;
+ case DO_ACCESS_METHOD:
+ dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
+ break;
case DO_OPCLASS:
dumpOpclass(fout, (OpclassInfo *) dobj);
break;
@@ -11446,6 +11526,59 @@ convertTSFunction(Archive *fout, Oid funcOid)
return result;
}
+/*
+ * dumpAccessMethod
+ * write out a single access method definition
+ */
+static void
+dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
+{
+ DumpOptions *dopt = fout->dopt;
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer labelq;
+ char *qamname;
+
+ /* Skip if not to be dumped */
+ if (!aminfo->dobj.dump || dopt->dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ labelq = createPQExpBuffer();
+
+ qamname = pg_strdup(fmtId(aminfo->dobj.name));
+
+ appendPQExpBuffer(q, "CREATE ACCESS METHOD %s HANDLER %s;\n",
+ qamname, aminfo->amhandler);
+
+ appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
+ qamname);
+
+ appendPQExpBuffer(labelq, "ACCESS METHOD %s",
+ qamname);
+
+ ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
+ aminfo->dobj.name,
+ NULL,
+ NULL,
+ "",
+ false, "ACCESS METHOD", SECTION_PRE_DATA,
+ q->data, delq->data, NULL,
+ NULL, 0,
+ NULL, NULL);
+
+ /* Dump Access Method Comments */
+ dumpComment(fout, labelq->data,
+ NULL, "",
+ aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
+
+ free(qamname);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(labelq);
+}
/*
* dumpOpclass
@@ -16227,6 +16360,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
case DO_FUNC:
case DO_AGG:
case DO_OPERATOR:
+ case DO_ACCESS_METHOD:
case DO_OPCLASS:
case DO_OPFAMILY:
case DO_COLLATION:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 9a1d8f8..0fb6087 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -48,6 +48,7 @@ typedef enum
DO_FUNC,
DO_AGG,
DO_OPERATOR,
+ DO_ACCESS_METHOD,
DO_OPCLASS,
DO_OPFAMILY,
DO_COLLATION,
@@ -167,6 +168,12 @@ typedef struct _oprInfo
Oid oprcode;
} OprInfo;
+typedef struct _accessMethodInfo
+{
+ DumpableObject dobj;
+ char *amhandler;
+} AccessMethodInfo;
+
typedef struct _opclassInfo
{
DumpableObject dobj;
@@ -548,6 +555,7 @@ extern TypeInfo *getTypes(Archive *fout, int *numTypes);
extern FuncInfo *getFuncs(Archive *fout, int *numFuncs);
extern AggInfo *getAggregates(Archive *fout, int *numAggregates);
extern OprInfo *getOperators(Archive *fout, int *numOperators);
+extern AccessMethodInfo *getAccessMethods(Archive *fout, int *numAccessMethods);
extern OpclassInfo *getOpclasses(Archive *fout, int *numOpclasses);
extern OpfamilyInfo *getOpfamilies(Archive *fout, int *numOpfamilies);
extern CollInfo *getCollations(Archive *fout, int *numCollations);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 78ff59c..3bd5bd8 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -45,6 +45,7 @@ static const int oldObjectTypePriority[] =
2, /* DO_FUNC */
3, /* DO_AGG */
3, /* DO_OPERATOR */
+ 3, /* DO_ACCESS_METHOD */
4, /* DO_OPCLASS */
4, /* DO_OPFAMILY */
4, /* DO_COLLATION */
@@ -95,6 +96,7 @@ static const int newObjectTypePriority[] =
6, /* DO_FUNC */
7, /* DO_AGG */
8, /* DO_OPERATOR */
+ 8, /* DO_ACCESS_METHOD */
9, /* DO_OPCLASS */
9, /* DO_OPFAMILY */
3, /* DO_COLLATION */
@@ -1329,6 +1331,10 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"OPERATOR %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
return;
+ case DO_ACCESS_METHOD:
+ snprintf(buf, bufsize,
+ "");
+ return;
case DO_OPCLASS:
snprintf(buf, bufsize,
"OPERATOR CLASS %s (ID %d OID %u)",
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 049bf9f..ac16740 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -153,10 +153,11 @@ typedef enum ObjectClass
OCLASS_EXTENSION, /* pg_extension */
OCLASS_EVENT_TRIGGER, /* pg_event_trigger */
OCLASS_POLICY, /* pg_policy */
- OCLASS_TRANSFORM /* pg_transform */
+ OCLASS_TRANSFORM, /* pg_transform */
+ OCLASS_AM, /* pg_am */
} ObjectClass;
-#define LAST_OCLASS OCLASS_TRANSFORM
+#define LAST_OCLASS OCLASS_AM
/* in dependency.c */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index f801c3e..f1bdee4 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -35,6 +35,13 @@ CATALOG(pg_am,2601)
{
NameData amname; /* access method name */
regproc amhandler; /* handler function */
+
+ /*----------
+ * Type of access method. Possible values are
+ * 'i': Index access method
+ *----------
+ */
+ char amtype;
} FormData_pg_am;
/* ----------------
@@ -48,31 +55,34 @@ typedef FormData_pg_am *Form_pg_am;
* compiler constants for pg_am
* ----------------
*/
-#define Natts_pg_am 2
+#define Natts_pg_am 3
#define Anum_pg_am_amname 1
#define Anum_pg_am_amhandler 2
+#define Anum_pg_am_amtype 3
+
+#define AMTYPE_INDEX 'i' /* index */
/* ----------------
* initial contents of pg_am
* ----------------
*/
-DATA(insert OID = 403 ( btree bthandler ));
+DATA(insert OID = 403 ( btree bthandler i ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
-DATA(insert OID = 405 ( hash hashhandler ));
+DATA(insert OID = 405 ( hash hashhandler i ));
DESCR("hash index access method");
#define HASH_AM_OID 405
-DATA(insert OID = 783 ( gist gisthandler ));
+DATA(insert OID = 783 ( gist gisthandler i ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
-DATA(insert OID = 2742 ( gin ginhandler ));
+DATA(insert OID = 2742 ( gin ginhandler i ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
-DATA(insert OID = 4000 ( spgist spghandler ));
+DATA(insert OID = 4000 ( spgist spghandler i ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
-DATA(insert OID = 3580 ( brin brinhandler ));
+DATA(insert OID = 3580 ( brin brinhandler i ));
DESCR("block range index (BRIN) access method");
#define BRIN_AM_OID 3580
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 54f67e9..1e21f03 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -91,8 +91,6 @@ extern void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
Oid opcnamespace);
extern void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
Oid opfnamespace);
-extern Oid get_am_oid(const char *amname, bool missing_ok);
-extern char *get_am_name(Oid amOid);
extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
@@ -137,6 +135,12 @@ extern Datum transformGenericOptions(Oid catalogId,
List *options,
Oid fdwvalidator);
+/* commands/amcmds.c */
+extern ObjectAddress CreateAccessMethod(CreateAmStmt *stmt);
+extern void RemoveAccessMethodById(Oid amOid);
+extern Oid get_am_oid(const char *amname, char amtype, bool missing_ok);
+extern char *get_am_name(Oid amOid);
+
/* support routines in commands/define.c */
extern char *defGetString(DefElem *def);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index c407fa2..7d46763 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -386,6 +386,7 @@ typedef enum NodeTag
T_CreatePolicyStmt,
T_AlterPolicyStmt,
T_CreateTransformStmt,
+ T_CreateAmStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2fd0629..8b958b4 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1379,6 +1379,7 @@ typedef struct SetOperationStmt
typedef enum ObjectType
{
+ OBJECT_ACCESS_METHOD,
OBJECT_AGGREGATE,
OBJECT_AMOP,
OBJECT_AMPROC,
@@ -2070,6 +2071,18 @@ typedef struct AlterPolicyStmt
Node *with_check; /* the policy's WITH CHECK condition. */
} AlterPolicyStmt;
+/*----------------------
+ * Create ACCESS METHOD Statement
+ *----------------------
+ */
+typedef struct CreateAmStmt
+{
+ NodeTag type;
+ char *amname; /* access method name */
+ List *handler_name; /* handler function name */
+ char amtype; /* type of access method */
+} CreateAmStmt;
+
/* ----------------------
* Create TRIGGER Statement
* ----------------------
--
1.9.1