Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)