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:
@@ -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
|
||||
|
Reference in New Issue
Block a user