Skip to content

Commit 4ad658c

Browse files
committed
Teach pg_dump to dump user-defined operator classes. For the moment,
this only works against 7.3 or later databases; the pushups required to do it without regprocedure/regtype/etc seem more trouble than they're worth, considering that existing users aren't expecting pg_dump support for this.
1 parent 2c2c43d commit 4ad658c

File tree

3 files changed

+342
-3
lines changed

3 files changed

+342
-3
lines changed

src/bin/pg_dump/common.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.66 2002/07/18 23:11:29 petere Exp $
14+
* $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.67 2002/07/30 21:56:04 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -60,13 +60,15 @@ dumpSchema(Archive *fout,
6060
int numInherits;
6161
int numAggregates;
6262
int numOperators;
63+
int numOpclasses;
6364
NamespaceInfo *nsinfo;
6465
TypeInfo *tinfo;
6566
FuncInfo *finfo;
6667
AggInfo *agginfo;
6768
TableInfo *tblinfo;
6869
InhInfo *inhinfo;
6970
OprInfo *oprinfo;
71+
OpclassInfo *opcinfo;
7072

7173
if (g_verbose)
7274
write_msg(NULL, "reading namespaces\n");
@@ -88,6 +90,10 @@ dumpSchema(Archive *fout,
8890
write_msg(NULL, "reading user-defined operators\n");
8991
oprinfo = getOperators(&numOperators);
9092

93+
if (g_verbose)
94+
write_msg(NULL, "reading user-defined operator classes\n");
95+
opcinfo = getOpclasses(&numOpclasses);
96+
9197
if (g_verbose)
9298
write_msg(NULL, "reading user-defined tables\n");
9399
tblinfo = getTables(&numTables);
@@ -170,6 +176,13 @@ dumpSchema(Archive *fout,
170176
dumpOprs(fout, oprinfo, numOperators);
171177
}
172178

179+
if (!dataOnly)
180+
{
181+
if (g_verbose)
182+
write_msg(NULL, "dumping out user-defined operator classes\n");
183+
dumpOpclasses(fout, opcinfo, numOpclasses);
184+
}
185+
173186
if (!dataOnly)
174187
{
175188
if (g_verbose)

src/bin/pg_dump/pg_dump.c

Lines changed: 316 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
*
2424
* IDENTIFICATION
25-
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.276 2002/07/25 20:52:59 petere Exp $
25+
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.277 2002/07/30 21:56:04 tgl Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -118,6 +118,7 @@ static void dumpOneOpr(Archive *fout, OprInfo *oprinfo,
118118
static const char *convertRegProcReference(const char *proc);
119119
static const char *convertOperatorReference(const char *opr,
120120
OprInfo *g_oprinfo, int numOperators);
121+
static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo);
121122
static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
122123
static Oid findLastBuiltinOid_V71(const char *);
123124
static Oid findLastBuiltinOid_V70(void);
@@ -1754,6 +1755,90 @@ getOperators(int *numOprs)
17541755
return oprinfo;
17551756
}
17561757

1758+
/*
1759+
* getOpclasses:
1760+
* read all opclasses in the system catalogs and return them in the
1761+
* OpclassInfo* structure
1762+
*
1763+
* numOpclasses is set to the number of opclasses read in
1764+
*/
1765+
OpclassInfo *
1766+
getOpclasses(int *numOpclasses)
1767+
{
1768+
PGresult *res;
1769+
int ntups;
1770+
int i;
1771+
PQExpBuffer query = createPQExpBuffer();
1772+
OpclassInfo *opcinfo;
1773+
int i_oid;
1774+
int i_opcname;
1775+
int i_opcnamespace;
1776+
int i_usename;
1777+
1778+
/*
1779+
* find all opclasses, including builtin opclasses;
1780+
* we filter out system-defined opclasses at dump-out time.
1781+
*/
1782+
1783+
/* Make sure we are in proper schema */
1784+
selectSourceSchema("pg_catalog");
1785+
1786+
if (g_fout->remoteVersion >= 70300)
1787+
{
1788+
appendPQExpBuffer(query, "SELECT pg_opclass.oid, opcname, "
1789+
"opcnamespace, "
1790+
"(select usename from pg_user where opcowner = usesysid) as usename "
1791+
"from pg_opclass");
1792+
}
1793+
else
1794+
{
1795+
appendPQExpBuffer(query, "SELECT pg_opclass.oid, opcname, "
1796+
"0::oid as opcnamespace, "
1797+
"''::name as usename "
1798+
"from pg_opclass");
1799+
}
1800+
1801+
res = PQexec(g_conn, query->data);
1802+
if (!res ||
1803+
PQresultStatus(res) != PGRES_TUPLES_OK)
1804+
{
1805+
write_msg(NULL, "query to obtain list of opclasses failed: %s", PQerrorMessage(g_conn));
1806+
exit_nicely();
1807+
}
1808+
1809+
ntups = PQntuples(res);
1810+
*numOpclasses = ntups;
1811+
1812+
opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
1813+
1814+
i_oid = PQfnumber(res, "oid");
1815+
i_opcname = PQfnumber(res, "opcname");
1816+
i_opcnamespace = PQfnumber(res, "opcnamespace");
1817+
i_usename = PQfnumber(res, "usename");
1818+
1819+
for (i = 0; i < ntups; i++)
1820+
{
1821+
opcinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1822+
opcinfo[i].opcname = strdup(PQgetvalue(res, i, i_opcname));
1823+
opcinfo[i].opcnamespace = findNamespace(PQgetvalue(res, i, i_opcnamespace),
1824+
opcinfo[i].oid);
1825+
opcinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1826+
1827+
if (g_fout->remoteVersion >= 70300)
1828+
{
1829+
if (strlen(opcinfo[i].usename) == 0)
1830+
write_msg(NULL, "WARNING: owner of opclass \"%s\" appears to be invalid\n",
1831+
opcinfo[i].opcname);
1832+
}
1833+
}
1834+
1835+
PQclear(res);
1836+
1837+
destroyPQExpBuffer(query);
1838+
1839+
return opcinfo;
1840+
}
1841+
17571842
/*
17581843
* getAggregates:
17591844
* read all the user-defined aggregates in the system catalogs and
@@ -3981,6 +4066,236 @@ convertOperatorReference(const char *opr,
39814066
return name;
39824067
}
39834068

4069+
4070+
/*
4071+
* dumpOpclasses
4072+
* writes out to fout the queries to recreate all the user-defined
4073+
* operator classes
4074+
*/
4075+
void
4076+
dumpOpclasses(Archive *fout, OpclassInfo *opcinfo, int numOpclasses)
4077+
{
4078+
int i;
4079+
4080+
for (i = 0; i < numOpclasses; i++)
4081+
{
4082+
/* Dump only opclasses in dumpable namespaces */
4083+
if (!opcinfo[i].opcnamespace->dump)
4084+
continue;
4085+
4086+
/* OK, dump it */
4087+
dumpOneOpclass(fout, &opcinfo[i]);
4088+
}
4089+
}
4090+
4091+
/*
4092+
* dumpOneOpclass
4093+
* write out a single operator class definition
4094+
*/
4095+
static void
4096+
dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
4097+
{
4098+
PQExpBuffer query = createPQExpBuffer();
4099+
PQExpBuffer q = createPQExpBuffer();
4100+
PQExpBuffer delq = createPQExpBuffer();
4101+
PGresult *res;
4102+
int ntups;
4103+
int i_opcintype;
4104+
int i_opckeytype;
4105+
int i_opcdefault;
4106+
int i_amname;
4107+
int i_amopstrategy;
4108+
int i_amopreqcheck;
4109+
int i_amopopr;
4110+
int i_amprocnum;
4111+
int i_amproc;
4112+
char *opcintype;
4113+
char *opckeytype;
4114+
char *opcdefault;
4115+
char *amname;
4116+
char *amopstrategy;
4117+
char *amopreqcheck;
4118+
char *amopopr;
4119+
char *amprocnum;
4120+
char *amproc;
4121+
bool needComma;
4122+
int i;
4123+
4124+
/*
4125+
* XXX currently we do not implement dumping of operator classes from
4126+
* pre-7.3 databases. This could be done but it seems not worth the
4127+
* trouble.
4128+
*/
4129+
if (g_fout->remoteVersion < 70300)
4130+
return;
4131+
4132+
/* Make sure we are in proper schema so regoperator works correctly */
4133+
selectSourceSchema(opcinfo->opcnamespace->nspname);
4134+
4135+
/* Get additional fields from the pg_opclass row */
4136+
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
4137+
"opckeytype::pg_catalog.regtype, "
4138+
"opcdefault, "
4139+
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
4140+
"FROM pg_catalog.pg_opclass "
4141+
"WHERE oid = '%s'::pg_catalog.oid",
4142+
opcinfo->oid);
4143+
4144+
res = PQexec(g_conn, query->data);
4145+
if (!res ||
4146+
PQresultStatus(res) != PGRES_TUPLES_OK)
4147+
{
4148+
write_msg(NULL, "query to obtain opclass details failed: %s", PQerrorMessage(g_conn));
4149+
exit_nicely();
4150+
}
4151+
4152+
/* Expecting a single result only */
4153+
ntups = PQntuples(res);
4154+
if (ntups != 1)
4155+
{
4156+
write_msg(NULL, "Got %d rows instead of one from: %s",
4157+
ntups, query->data);
4158+
exit_nicely();
4159+
}
4160+
4161+
i_opcintype = PQfnumber(res, "opcintype");
4162+
i_opckeytype = PQfnumber(res, "opckeytype");
4163+
i_opcdefault = PQfnumber(res, "opcdefault");
4164+
i_amname = PQfnumber(res, "amname");
4165+
4166+
opcintype = PQgetvalue(res, 0, i_opcintype);
4167+
opckeytype = PQgetvalue(res, 0, i_opckeytype);
4168+
opcdefault = PQgetvalue(res, 0, i_opcdefault);
4169+
amname = PQgetvalue(res, 0, i_amname);
4170+
4171+
/* DROP must be fully qualified in case same name appears in pg_catalog */
4172+
appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
4173+
fmtId(opcinfo->opcnamespace->nspname, force_quotes));
4174+
appendPQExpBuffer(delq, ".%s",
4175+
fmtId(opcinfo->opcname, force_quotes));
4176+
appendPQExpBuffer(delq, " USING %s;\n",
4177+
fmtId(amname, force_quotes));
4178+
4179+
/* Build the fixed portion of the CREATE command */
4180+
appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n\t",
4181+
fmtId(opcinfo->opcname, force_quotes));
4182+
if (strcmp(opcdefault, "t") == 0)
4183+
appendPQExpBuffer(q, "DEFAULT ");
4184+
appendPQExpBuffer(q, "FOR TYPE %s USING %s AS\n\t",
4185+
opcintype,
4186+
fmtId(amname, force_quotes));
4187+
4188+
needComma = false;
4189+
4190+
if (strcmp(opckeytype, "-") != 0)
4191+
{
4192+
appendPQExpBuffer(q, "STORAGE\t%s",
4193+
opckeytype);
4194+
needComma = true;
4195+
}
4196+
4197+
PQclear(res);
4198+
4199+
/*
4200+
* Now fetch and print the OPERATOR entries (pg_amop rows).
4201+
*/
4202+
resetPQExpBuffer(query);
4203+
4204+
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
4205+
"amopopr::pg_catalog.regoperator "
4206+
"FROM pg_catalog.pg_amop "
4207+
"WHERE amopclaid = '%s'::pg_catalog.oid "
4208+
"ORDER BY amopstrategy",
4209+
opcinfo->oid);
4210+
4211+
res = PQexec(g_conn, query->data);
4212+
if (!res ||
4213+
PQresultStatus(res) != PGRES_TUPLES_OK)
4214+
{
4215+
write_msg(NULL, "query to obtain opclass operators failed: %s", PQerrorMessage(g_conn));
4216+
exit_nicely();
4217+
}
4218+
4219+
ntups = PQntuples(res);
4220+
4221+
i_amopstrategy = PQfnumber(res, "amopstrategy");
4222+
i_amopreqcheck = PQfnumber(res, "amopreqcheck");
4223+
i_amopopr = PQfnumber(res, "amopopr");
4224+
4225+
for (i = 0; i < ntups; i++)
4226+
{
4227+
amopstrategy = PQgetvalue(res, i, i_amopstrategy);
4228+
amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
4229+
amopopr = PQgetvalue(res, i, i_amopopr);
4230+
4231+
if (needComma)
4232+
appendPQExpBuffer(q, " ,\n\t");
4233+
4234+
appendPQExpBuffer(q, "OPERATOR\t%s\t%s",
4235+
amopstrategy, amopopr);
4236+
if (strcmp(amopreqcheck, "t") == 0)
4237+
appendPQExpBuffer(q, "\tRECHECK");
4238+
4239+
needComma = true;
4240+
}
4241+
4242+
PQclear(res);
4243+
4244+
/*
4245+
* Now fetch and print the FUNCTION entries (pg_amproc rows).
4246+
*/
4247+
resetPQExpBuffer(query);
4248+
4249+
appendPQExpBuffer(query, "SELECT amprocnum, "
4250+
"amproc::pg_catalog.regprocedure "
4251+
"FROM pg_catalog.pg_amproc "
4252+
"WHERE amopclaid = '%s'::pg_catalog.oid "
4253+
"ORDER BY amprocnum",
4254+
opcinfo->oid);
4255+
4256+
res = PQexec(g_conn, query->data);
4257+
if (!res ||
4258+
PQresultStatus(res) != PGRES_TUPLES_OK)
4259+
{
4260+
write_msg(NULL, "query to obtain opclass functions failed: %s", PQerrorMessage(g_conn));
4261+
exit_nicely();
4262+
}
4263+
4264+
ntups = PQntuples(res);
4265+
4266+
i_amprocnum = PQfnumber(res, "amprocnum");
4267+
i_amproc = PQfnumber(res, "amproc");
4268+
4269+
for (i = 0; i < ntups; i++)
4270+
{
4271+
amprocnum = PQgetvalue(res, i, i_amprocnum);
4272+
amproc = PQgetvalue(res, i, i_amproc);
4273+
4274+
if (needComma)
4275+
appendPQExpBuffer(q, " ,\n\t");
4276+
4277+
appendPQExpBuffer(q, "FUNCTION\t%s\t%s",
4278+
amprocnum, amproc);
4279+
4280+
needComma = true;
4281+
}
4282+
4283+
PQclear(res);
4284+
4285+
appendPQExpBuffer(q, " ;\n");
4286+
4287+
ArchiveEntry(fout, opcinfo->oid, opcinfo->opcname,
4288+
opcinfo->opcnamespace->nspname, opcinfo->usename,
4289+
"OPERATOR CLASS", NULL,
4290+
q->data, delq->data,
4291+
NULL, NULL, NULL);
4292+
4293+
destroyPQExpBuffer(query);
4294+
destroyPQExpBuffer(q);
4295+
destroyPQExpBuffer(delq);
4296+
}
4297+
4298+
39844299
/*
39854300
* dumpAggs
39864301
* writes out to fout the queries to create all the user-defined aggregates

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy