1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-02 04:21:28 +03:00

SQL/MED catalog manipulation facilities

This doesn't do any remote or external things yet, but it gives modules
like plproxy and dblink a standardized and future-proof system for
managing their connection information.

Martin Pihlak and Peter Eisentraut
This commit is contained in:
Peter Eisentraut
2008-12-19 16:25:19 +00:00
parent 1eec10a2de
commit cae565e503
76 changed files with 8452 additions and 125 deletions

View File

@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.508 2008/12/18 18:20:34 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.509 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -158,6 +158,11 @@ static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
static void dumpUserMappings(Archive *fout, const char *target,
const char *servername, const char *namespace,
const char *owner, CatalogId catalogId, DumpId dumpId);
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name,
@@ -5269,6 +5274,165 @@ getTSConfigurations(int *numTSConfigs)
return cfginfo;
}
/*
* getForeignDataWrappers:
* read all foreign-data wrappers in the system catalogs and return
* them in the FdwInfo* structure
*
* numForeignDataWrappers is set to the number of fdws read in
*/
FdwInfo *
getForeignDataWrappers(int *numForeignDataWrappers)
{
PGresult *res;
int ntups;
int i;
PQExpBuffer query = createPQExpBuffer();
FdwInfo *fdwinfo;
int i_oid;
int i_fdwname;
int i_rolname;
int i_fdwlibrary;
int i_fdwacl;
int i_fdwoptions;
/* Before 8.4, there are no foreign-data wrappers */
if (g_fout->remoteVersion < 80400)
{
*numForeignDataWrappers = 0;
return NULL;
}
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
appendPQExpBuffer(query, "SELECT oid, fdwname, "
"(%s fdwowner) as rolname, fdwlibrary, fdwacl,"
"array_to_string(ARRAY(select option_name || ' ' || quote_literal(option_value) from pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
"FROM pg_foreign_data_wrapper",
username_subquery);
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
*numForeignDataWrappers = ntups;
fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
i_oid = PQfnumber(res, "oid");
i_fdwname = PQfnumber(res, "fdwname");
i_rolname = PQfnumber(res, "rolname");
i_fdwlibrary = PQfnumber(res, "fdwlibrary");
i_fdwacl = PQfnumber(res, "fdwacl");
i_fdwoptions = PQfnumber(res, "fdwoptions");
for (i = 0; i < ntups; i++)
{
fdwinfo[i].dobj.objType = DO_FDW;
fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&fdwinfo[i].dobj);
fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
fdwinfo[i].dobj.namespace = NULL;
fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
fdwinfo[i].fdwlibrary = strdup(PQgetvalue(res, i, i_fdwlibrary));
fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
/* Decide whether we want to dump it */
selectDumpableObject(&(fdwinfo[i].dobj));
}
PQclear(res);
destroyPQExpBuffer(query);
return fdwinfo;
}
/*
* getForeignServers:
* read all foreign servers in the system catalogs and return
* them in the ForeignServerInfo * structure
*
* numForeignServers is set to the number of servers read in
*/
ForeignServerInfo *
getForeignServers(int *numForeignServers)
{
PGresult *res;
int ntups;
int i;
PQExpBuffer query = createPQExpBuffer();
ForeignServerInfo *srvinfo;
int i_oid;
int i_srvname;
int i_rolname;
int i_srvfdw;
int i_srvtype;
int i_srvversion;
int i_srvacl;
int i_srvoptions;
/* Before 8.4, there are no foreign servers */
if (g_fout->remoteVersion < 80400)
{
*numForeignServers = 0;
return NULL;
}
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
appendPQExpBuffer(query, "SELECT oid, srvname, "
"(%s srvowner) as rolname, "
"srvfdw, srvtype, srvversion, srvacl,"
"array_to_string(ARRAY(select option_name || ' ' || quote_literal(option_value) from pg_options_to_table(srvoptions)), ', ') as srvoptions "
"FROM pg_foreign_server",
username_subquery);
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
*numForeignServers = ntups;
srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
i_oid = PQfnumber(res, "oid");
i_srvname = PQfnumber(res, "srvname");
i_rolname = PQfnumber(res, "rolname");
i_srvfdw = PQfnumber(res, "srvfdw");
i_srvtype = PQfnumber(res, "srvtype");
i_srvversion = PQfnumber(res, "srvversion");
i_srvacl = PQfnumber(res, "srvacl");
i_srvoptions = PQfnumber(res, "srvoptions");
for (i = 0; i < ntups; i++)
{
srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&srvinfo[i].dobj);
srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
srvinfo[i].dobj.namespace = NULL;
srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
/* Decide whether we want to dump it */
selectDumpableObject(&(srvinfo[i].dobj));
}
PQclear(res);
destroyPQExpBuffer(query);
return srvinfo;
}
/*
* dumpComment --
@@ -5671,6 +5835,12 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_TSCONFIG:
dumpTSConfig(fout, (TSConfigInfo *) dobj);
break;
case DO_FDW:
dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
break;
case DO_FOREIGN_SERVER:
dumpForeignServer(fout, (ForeignServerInfo *) dobj);
break;
case DO_BLOBS:
ArchiveEntry(fout, dobj->catId, dobj->dumpId,
dobj->name, NULL, NULL, "",
@@ -8977,6 +9147,224 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
destroyPQExpBuffer(query);
}
/*
* dumpForeignDataWrapper
* write out a single foreign-data wrapper definition
*/
static void
dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
{
PQExpBuffer q;
PQExpBuffer delq;
char *namecopy;
/* Skip if not to be dumped */
if (!fdwinfo->dobj.dump || dataOnly)
return;
q = createPQExpBuffer();
delq = createPQExpBuffer();
appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s LIBRARY '%s' LANGUAGE C",
fmtId(fdwinfo->dobj.name), fdwinfo->fdwlibrary);
if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
appendPQExpBuffer(q, ";\n");
appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
fmtId(fdwinfo->dobj.name));
ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
fdwinfo->dobj.name,
NULL,
NULL,
fdwinfo->rolname,
false, "FOREIGN DATA WRAPPER", q->data, delq->data, NULL,
fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
NULL, NULL);
/* Handle the ACL */
namecopy = strdup(fmtId(fdwinfo->dobj.name));
dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
"FOREIGN DATA WRAPPER",
namecopy, fdwinfo->dobj.name,
NULL, fdwinfo->rolname,
fdwinfo->fdwacl);
free(namecopy);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
}
/*
* dumpForeignServer
* write out a foreign server definition
*/
static void
dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
{
PQExpBuffer q;
PQExpBuffer delq;
PQExpBuffer query;
PGresult *res;
int ntups;
char *namecopy;
char *fdwname;
/* Skip if not to be dumped */
if (!srvinfo->dobj.dump || dataOnly)
return;
q = createPQExpBuffer();
delq = createPQExpBuffer();
query = createPQExpBuffer();
/* look up the foreign-data wrapper */
appendPQExpBuffer(query, "SELECT fdwname "
"FROM pg_foreign_data_wrapper w "
"WHERE w.oid = '%u'",
srvinfo->srvfdw);
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
if (ntups != 1)
{
write_msg(NULL, "query returned %d rows instead of one: %s\n",
ntups, query->data);
exit_nicely();
}
fdwname = PQgetvalue(res, 0, 0);
appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
appendPQExpBuffer(q, " TYPE '%s'", srvinfo->srvtype);
if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
appendPQExpBuffer(q, " VERSION '%s'", srvinfo->srvversion);
appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
appendPQExpBuffer(q, "%s", fmtId(fdwname));
if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
appendPQExpBuffer(q, ";\n");
appendPQExpBuffer(delq, "DROP SERVER %s;\n",
fmtId(srvinfo->dobj.name));
ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
srvinfo->dobj.name,
NULL,
NULL,
srvinfo->rolname,
false, "SERVER", q->data, delq->data, NULL,
srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
NULL, NULL);
/* Handle the ACL */
namecopy = strdup(fmtId(srvinfo->dobj.name));
dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
"SERVER",
namecopy, srvinfo->dobj.name,
NULL, srvinfo->rolname,
srvinfo->srvacl);
free(namecopy);
/* Dump user mappings */
resetPQExpBuffer(q);
appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
dumpUserMappings(fout, q->data,
srvinfo->dobj.name, NULL,
srvinfo->rolname,
srvinfo->dobj.catId, srvinfo->dobj.dumpId);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
}
/*
* dumpUserMappings
*
* This routine is used to dump any user mappings associated with the
* server handed to this routine. Should be called after ArchiveEntry()
* for the server.
*/
static void
dumpUserMappings(Archive *fout, const char *target,
const char *servername, const char *namespace,
const char *owner,
CatalogId catalogId, DumpId dumpId)
{
PQExpBuffer q;
PQExpBuffer delq;
PQExpBuffer query;
PQExpBuffer tag;
PGresult *res;
int ntups;
int i_umuser;
int i_umoptions;
int i;
q = createPQExpBuffer();
tag = createPQExpBuffer();
delq = createPQExpBuffer();
query = createPQExpBuffer();
appendPQExpBuffer(query,
"SELECT (%s umuser) AS umuser, "
"array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
"FROM pg_user_mapping WHERE umserver=%u",
username_subquery,
catalogId.oid);
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
i_umuser = PQfnumber(res, "umuser");
i_umoptions = PQfnumber(res, "umoptions");
for (i = 0; i < ntups; i++)
{
char *umuser;
char *umoptions;
umuser = PQgetvalue(res, i, i_umuser);
umoptions = PQgetvalue(res, i, i_umoptions);
resetPQExpBuffer(q);
appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
if (umoptions && strlen(umoptions) > 0)
appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
appendPQExpBuffer(q, ";\n");
resetPQExpBuffer(delq);
appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
resetPQExpBuffer(tag);
appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
ArchiveEntry(fout, nilCatalogId, createDumpId(),
tag->data,
namespace,
NULL,
owner, false,
"USER MAPPING", q->data,
delq->data, NULL,
&dumpId, 1,
NULL, NULL);
}
PQclear(res);
destroyPQExpBuffer(query);
destroyPQExpBuffer(delq);
destroyPQExpBuffer(q);
}
/*----------
* Write out grant/revoke information