summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorAlvaro Herrera2016-03-24 02:01:35 +0000
committerAlvaro Herrera2016-03-24 02:01:35 +0000
commit473b93287040b20017cc25a157cffdc5b978c254 (patch)
tree58f662a65247525b2e5e178b9050feb3f3056590 /src/bin
parent2c6af4f44228d76d3351fe26f68b00b55cdd239a (diff)
Support CREATE ACCESS METHOD
This enables external code to create access methods. This is useful so that extensions can add their own access methods which can be formally tracked for dependencies, so that DROP operates correctly. Also, having explicit support makes pg_dump work correctly. Currently only index AMs are supported, but we expect different types to be added in the future. Authors: Alexander Korotkov, Petr Jelínek Reviewed-By: Teodor Sigaev, Petr Jelínek, Jim Nasby Commitfest-URL: https://commitfest.postgresql.org/9/353/ Discussion: https://www.postgresql.org/message-id/CAPpHfdsXwZmojm6Dx+TJnpYk27kT4o7Ri6X_4OSWcByu1Rm+VA@mail.gmail.com
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/pg_dump/common.c5
-rw-r--r--src/bin/pg_dump/pg_dump.c172
-rw-r--r--src/bin/pg_dump/pg_dump.h9
-rw-r--r--src/bin/pg_dump/pg_dump_sort.c11
4 files changed, 195 insertions, 2 deletions
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index f798b15e3c4..1acd91ab444 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 64c2673f9a5..b3ef201a3ae 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -45,6 +45,7 @@
#include "access/attnum.h"
#include "access/sysattr.h"
#include "access/transam.h"
+#include "catalog/pg_am.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_class.h"
#include "catalog/pg_default_acl.h"
@@ -173,6 +174,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);
@@ -1469,6 +1471,26 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
}
/*
+ * selectDumpableAccessMethod: policy-setting subroutine
+ * Mark an access method as to be dumped or not
+ *
+ * Access methods do not belong to any particular namespace. To identify
+ * built-in access methods, we must resort to checking whether the
+ * method's OID is in the range reserved for initdb.
+ */
+static void
+selectDumpableAccessMethod(AccessMethodInfo *method, DumpOptions *dopt)
+{
+ if (checkExtensionMembership(&method->dobj, dopt))
+ return; /* extension membership overrides all else */
+
+ if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
+ method->dobj.dump = false;
+ else
+ method->dobj.dump = dopt->include_everything;
+}
+
+/*
* selectDumpableExtension: policy-setting subroutine
* Mark an extension as to be dumped or not
*
@@ -4101,6 +4123,84 @@ 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;
+ int i_amtype;
+
+ /* 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, amtype, "
+ "amhandler::pg_catalog.regproc AS amhandler "
+ "FROM pg_am");
+
+ 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");
+ i_amtype = PQfnumber(res, "amtype");
+
+ 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));
+ aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
+
+ /* Decide whether we want to dump it */
+ selectDumpableAccessMethod(&(aminfo[i]), dopt);
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return aminfo;
+}
+
+
+/*
* getOpclasses:
* read all opclasses in the system catalogs and return them in the
* OpclassInfo* structure
@@ -8408,6 +8508,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 +11549,74 @@ 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 ", qamname);
+
+ switch (aminfo->amtype)
+ {
+ case AMTYPE_INDEX:
+ appendPQExpBuffer(q, "TYPE INDEX ");
+ break;
+ default:
+ write_msg(NULL, "WARNING: invalid type %c of access method %s\n",
+ aminfo->amtype, qamname);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(labelq);
+ return;
+ }
+
+ appendPQExpBuffer(q, "HANDLER %s;\n", 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 +16398,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 9a1d8f863cc..66e693183ae 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,13 @@ typedef struct _oprInfo
Oid oprcode;
} OprInfo;
+typedef struct _accessMethodInfo
+{
+ DumpableObject dobj;
+ char amtype;
+ char *amhandler;
+} AccessMethodInfo;
+
typedef struct _opclassInfo
{
DumpableObject dobj;
@@ -548,6 +556,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 78ff59c3429..36de6b62573 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -28,8 +28,8 @@ static const char *modulename = gettext_noop("sorter");
* by OID. (This is a relatively crude hack to provide semi-reasonable
* behavior for old databases without full dependency info.) Note: collations,
* extensions, text search, foreign-data, materialized view, event trigger,
- * policies, transforms, and default ACL objects can't really happen here, so the rather
- * bogus priorities for them don't matter.
+ * policies, transforms, access methods and default ACL objects can't really
+ * happen here, so the rather bogus priorities for them don't matter.
*
* NOTE: object-type priorities must match the section assignments made in
* pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
@@ -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,11 @@ 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,
+ "ACCESS METHOD %s (ID %d OID %u)",
+ obj->name, obj->dumpId, obj->catId.oid);
+ return;
case DO_OPCLASS:
snprintf(buf, bufsize,
"OPERATOR CLASS %s (ID %d OID %u)",