|
22 | 22 | *
|
23 | 23 | *
|
24 | 24 | * 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 $ |
26 | 26 | *
|
27 | 27 | *-------------------------------------------------------------------------
|
28 | 28 | */
|
@@ -118,6 +118,7 @@ static void dumpOneOpr(Archive *fout, OprInfo *oprinfo,
|
118 | 118 | static const char *convertRegProcReference(const char *proc);
|
119 | 119 | static const char *convertOperatorReference(const char *opr,
|
120 | 120 | OprInfo *g_oprinfo, int numOperators);
|
| 121 | +static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo); |
121 | 122 | static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
|
122 | 123 | static Oid findLastBuiltinOid_V71(const char *);
|
123 | 124 | static Oid findLastBuiltinOid_V70(void);
|
@@ -1754,6 +1755,90 @@ getOperators(int *numOprs)
|
1754 | 1755 | return oprinfo;
|
1755 | 1756 | }
|
1756 | 1757 |
|
| 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 | + |
1757 | 1842 | /*
|
1758 | 1843 | * getAggregates:
|
1759 | 1844 | * read all the user-defined aggregates in the system catalogs and
|
@@ -3981,6 +4066,236 @@ convertOperatorReference(const char *opr,
|
3981 | 4066 | return name;
|
3982 | 4067 | }
|
3983 | 4068 |
|
| 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 | + |
3984 | 4299 | /*
|
3985 | 4300 | * dumpAggs
|
3986 | 4301 | * writes out to fout the queries to create all the user-defined aggregates
|
|
0 commit comments