|
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 | staticconstchar*convertRegProcReference(constchar*proc);
|
119 | 119 | staticconstchar*convertOperatorReference(constchar*opr,
|
120 | 120 | OprInfo*g_oprinfo,intnumOperators);
|
| 121 | +staticvoiddumpOneOpclass(Archive*fout,OpclassInfo*opcinfo); |
121 | 122 | staticvoiddumpOneAgg(Archive*fout,AggInfo*agginfo);
|
122 | 123 | staticOidfindLastBuiltinOid_V71(constchar*);
|
123 | 124 | staticOidfindLastBuiltinOid_V70(void);
|
@@ -1754,6 +1755,90 @@ getOperators(int *numOprs)
|
1754 | 1755 | returnoprinfo;
|
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 | +intntups; |
| 1770 | +inti; |
| 1771 | +PQExpBufferquery=createPQExpBuffer(); |
| 1772 | +OpclassInfo*opcinfo; |
| 1773 | +inti_oid; |
| 1774 | +inti_opcname; |
| 1775 | +inti_opcnamespace; |
| 1776 | +inti_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 | +returnopcinfo; |
| 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 | returnname;
|
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,intnumOpclasses) |
| 4077 | +{ |
| 4078 | +inti; |
| 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 | +staticvoid |
| 4096 | +dumpOneOpclass(Archive*fout,OpclassInfo*opcinfo) |
| 4097 | +{ |
| 4098 | +PQExpBufferquery=createPQExpBuffer(); |
| 4099 | +PQExpBufferq=createPQExpBuffer(); |
| 4100 | +PQExpBufferdelq=createPQExpBuffer(); |
| 4101 | +PGresult*res; |
| 4102 | +intntups; |
| 4103 | +inti_opcintype; |
| 4104 | +inti_opckeytype; |
| 4105 | +inti_opcdefault; |
| 4106 | +inti_amname; |
| 4107 | +inti_amopstrategy; |
| 4108 | +inti_amopreqcheck; |
| 4109 | +inti_amopopr; |
| 4110 | +inti_amprocnum; |
| 4111 | +inti_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 | +boolneedComma; |
| 4122 | +inti; |
| 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
|
|