4 * Copyright (c) 2002-2018, PostgreSQL Global Development Group
6 * src/tools/findoidjoins/findoidjoins.c
8 #include "postgres_fe.h"
10 #include "catalog/pg_class.h"
12 #include "fe_utils/connect.h"
14 #include "pqexpbuffer.h"
18 main(int argc, char **argv)
31 pk; /* loop counters */
35 fprintf(stderr, "Usage: %s database\n", argv[0]);
39 initPQExpBuffer(&sql);
41 appendPQExpBuffer(&sql, "dbname=%s", argv[1]);
43 conn = PQconnectdb(sql.data);
44 if (PQstatus(conn) == CONNECTION_BAD)
46 fprintf(stderr, "connection error: %s\n", PQerrorMessage(conn));
50 res = PQexec(conn, ALWAYS_SECURE_SEARCH_PATH_SQL);
51 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
53 fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn));
58 /* Get a list of relations that have OIDs */
60 printfPQExpBuffer(&sql, "%s",
61 "SET search_path = public;"
62 "SELECT c.relname, (SELECT nspname FROM "
63 "pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
64 "FROM pg_catalog.pg_class c "
65 "WHERE c.relkind = " CppAsString2(RELKIND_RELATION)
67 "ORDER BY nspname, c.relname"
70 res = PQexec(conn, sql.data);
71 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
73 fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn));
78 /* Get a list of columns of OID type (or any OID-alias type) */
80 printfPQExpBuffer(&sql, "%s",
82 "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
84 "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
86 " AND c.relkind = " CppAsString2(RELKIND_RELATION)
87 " AND a.attrelid = c.oid"
88 " AND a.atttypid IN ('pg_catalog.oid'::regtype, "
89 " 'pg_catalog.regclass'::regtype, "
90 " 'pg_catalog.regoper'::regtype, "
91 " 'pg_catalog.regoperator'::regtype, "
92 " 'pg_catalog.regproc'::regtype, "
93 " 'pg_catalog.regprocedure'::regtype, "
94 " 'pg_catalog.regtype'::regtype, "
95 " 'pg_catalog.regconfig'::regtype, "
96 " 'pg_catalog.regdictionary'::regtype) "
97 "ORDER BY nspname, c.relname, a.attnum"
100 res = PQexec(conn, sql.data);
101 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
103 fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn));
109 * For each column and each relation-having-OIDs, look to see if the
110 * column contains any values matching entries in the relation.
113 for (fk = 0; fk < PQntuples(fkrel_res); fk++)
115 fk_relname = PQgetvalue(fkrel_res, fk, 0);
116 fk_nspname = PQgetvalue(fkrel_res, fk, 1);
117 fk_attname = PQgetvalue(fkrel_res, fk, 2);
119 for (pk = 0; pk < PQntuples(pkrel_res); pk++)
121 pk_relname = PQgetvalue(pkrel_res, pk, 0);
122 pk_nspname = PQgetvalue(pkrel_res, pk, 1);
124 printfPQExpBuffer(&sql,
126 "FROM \"%s\".\"%s\" t1, "
128 "WHERE t1.\"%s\"::pg_catalog.oid = t2.oid "
130 fk_nspname, fk_relname,
131 pk_nspname, pk_relname,
134 res = PQexec(conn, sql.data);
135 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
137 fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn));
141 if (PQntuples(res) != 0)
142 printf("Join %s.%s.%s => %s.%s.oid\n",
143 fk_nspname, fk_relname, fk_attname,
144 pk_nspname, pk_relname);
152 /* Now, do the same for referencing columns that are arrays */
154 /* Get a list of columns of OID-array type (or any OID-alias type) */
156 printfPQExpBuffer(&sql, "%s",
158 "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
160 "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
162 " AND c.relkind = " CppAsString2(RELKIND_RELATION)
163 " AND a.attrelid = c.oid"
164 " AND a.atttypid IN ('pg_catalog.oid[]'::regtype, "
165 " 'pg_catalog.regclass[]'::regtype, "
166 " 'pg_catalog.regoper[]'::regtype, "
167 " 'pg_catalog.regoperator[]'::regtype, "
168 " 'pg_catalog.regproc[]'::regtype, "
169 " 'pg_catalog.regprocedure[]'::regtype, "
170 " 'pg_catalog.regtype[]'::regtype, "
171 " 'pg_catalog.regconfig[]'::regtype, "
172 " 'pg_catalog.regdictionary[]'::regtype) "
173 "ORDER BY nspname, c.relname, a.attnum"
176 res = PQexec(conn, sql.data);
177 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
179 fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn));
185 * For each column and each relation-having-OIDs, look to see if the
186 * column contains any values matching entries in the relation.
189 for (fk = 0; fk < PQntuples(fkrel_res); fk++)
191 fk_relname = PQgetvalue(fkrel_res, fk, 0);
192 fk_nspname = PQgetvalue(fkrel_res, fk, 1);
193 fk_attname = PQgetvalue(fkrel_res, fk, 2);
195 for (pk = 0; pk < PQntuples(pkrel_res); pk++)
197 pk_relname = PQgetvalue(pkrel_res, pk, 0);
198 pk_nspname = PQgetvalue(pkrel_res, pk, 1);
200 printfPQExpBuffer(&sql,
202 "FROM \"%s\".\"%s\" t1, "
204 "WHERE t2.oid = ANY(t1.\"%s\")"
206 fk_nspname, fk_relname,
207 pk_nspname, pk_relname,
210 res = PQexec(conn, sql.data);
211 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
213 fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn));
217 if (PQntuples(res) != 0)
218 printf("Join %s.%s.%s []=> %s.%s.oid\n",
219 fk_nspname, fk_relname, fk_attname,
220 pk_nspname, pk_relname);
232 termPQExpBuffer(&sql);