Header And Logo

PostgreSQL
| The world's most advanced open source database.

findoidjoins.c

Go to the documentation of this file.
00001 /*
00002  * findoidjoins.c
00003  *
00004  * Copyright (c) 2002-2013, PostgreSQL Global Development Group
00005  *
00006  * src/tools/findoidjoins/findoidjoins.c
00007  */
00008 #include "postgres_fe.h"
00009 
00010 #include "libpq-fe.h"
00011 #include "pqexpbuffer.h"
00012 
00013 
00014 int
00015 main(int argc, char **argv)
00016 {
00017     PGconn     *conn;
00018     PQExpBufferData sql;
00019     PGresult   *res;
00020     PGresult   *pkrel_res;
00021     PGresult   *fkrel_res;
00022     char       *fk_relname;
00023     char       *fk_nspname;
00024     char       *fk_attname;
00025     char       *pk_relname;
00026     char       *pk_nspname;
00027     int         fk,
00028                 pk;             /* loop counters */
00029 
00030     if (argc != 2)
00031     {
00032         fprintf(stderr, "Usage:  %s database\n", argv[0]);
00033         exit(EXIT_FAILURE);
00034     }
00035 
00036     initPQExpBuffer(&sql);
00037 
00038     appendPQExpBuffer(&sql, "dbname=%s", argv[1]);
00039 
00040     conn = PQconnectdb(sql.data);
00041     if (PQstatus(conn) == CONNECTION_BAD)
00042     {
00043         fprintf(stderr, "connection error:  %s\n", PQerrorMessage(conn));
00044         exit(EXIT_FAILURE);
00045     }
00046 
00047     /* Get a list of relations that have OIDs */
00048 
00049     printfPQExpBuffer(&sql, "%s",
00050                       "SET search_path = public;"
00051                       "SELECT c.relname, (SELECT nspname FROM "
00052         "pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
00053                       "FROM pg_catalog.pg_class c "
00054                       "WHERE c.relkind = 'r' "
00055                       "AND c.relhasoids "
00056                       "ORDER BY nspname, c.relname"
00057         );
00058 
00059     res = PQexec(conn, sql.data);
00060     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
00061     {
00062         fprintf(stderr, "sql error:  %s\n", PQerrorMessage(conn));
00063         exit(EXIT_FAILURE);
00064     }
00065     pkrel_res = res;
00066 
00067     /* Get a list of columns of OID type (or any OID-alias type) */
00068 
00069     printfPQExpBuffer(&sql, "%s",
00070                       "SELECT c.relname, "
00071                       "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
00072                       "a.attname "
00073                       "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
00074                       "WHERE a.attnum > 0 AND c.relkind = 'r' "
00075                       "AND a.attrelid = c.oid "
00076                       "AND a.atttypid IN ('pg_catalog.oid'::regtype, "
00077                       " 'pg_catalog.regclass'::regtype, "
00078                       " 'pg_catalog.regoper'::regtype, "
00079                       " 'pg_catalog.regoperator'::regtype, "
00080                       " 'pg_catalog.regproc'::regtype, "
00081                       " 'pg_catalog.regprocedure'::regtype, "
00082                       " 'pg_catalog.regtype'::regtype, "
00083                       " 'pg_catalog.regconfig'::regtype, "
00084                       " 'pg_catalog.regdictionary'::regtype) "
00085                       "ORDER BY nspname, c.relname, a.attnum"
00086         );
00087 
00088     res = PQexec(conn, sql.data);
00089     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
00090     {
00091         fprintf(stderr, "sql error:  %s\n", PQerrorMessage(conn));
00092         exit(EXIT_FAILURE);
00093     }
00094     fkrel_res = res;
00095 
00096     /*
00097      * For each column and each relation-having-OIDs, look to see if the
00098      * column contains any values matching entries in the relation.
00099      */
00100 
00101     for (fk = 0; fk < PQntuples(fkrel_res); fk++)
00102     {
00103         fk_relname = PQgetvalue(fkrel_res, fk, 0);
00104         fk_nspname = PQgetvalue(fkrel_res, fk, 1);
00105         fk_attname = PQgetvalue(fkrel_res, fk, 2);
00106 
00107         for (pk = 0; pk < PQntuples(pkrel_res); pk++)
00108         {
00109             pk_relname = PQgetvalue(pkrel_res, pk, 0);
00110             pk_nspname = PQgetvalue(pkrel_res, pk, 1);
00111 
00112             printfPQExpBuffer(&sql,
00113                               "SELECT   1 "
00114                               "FROM \"%s\".\"%s\" t1, "
00115                               "\"%s\".\"%s\" t2 "
00116                               "WHERE t1.\"%s\"::pg_catalog.oid = t2.oid "
00117                               "LIMIT 1",
00118                               fk_nspname, fk_relname,
00119                               pk_nspname, pk_relname,
00120                               fk_attname);
00121 
00122             res = PQexec(conn, sql.data);
00123             if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
00124             {
00125                 fprintf(stderr, "sql error:  %s\n", PQerrorMessage(conn));
00126                 exit(EXIT_FAILURE);
00127             }
00128 
00129             if (PQntuples(res) != 0)
00130                 printf("Join %s.%s.%s => %s.%s.oid\n",
00131                        fk_nspname, fk_relname, fk_attname,
00132                        pk_nspname, pk_relname);
00133 
00134             PQclear(res);
00135         }
00136     }
00137 
00138     PQclear(fkrel_res);
00139 
00140     /* Now, do the same for referencing columns that are arrays */
00141 
00142     /* Get a list of columns of OID-array type (or any OID-alias type) */
00143 
00144     printfPQExpBuffer(&sql, "%s",
00145                       "SELECT c.relname, "
00146                       "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
00147                       "a.attname "
00148                       "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
00149                       "WHERE a.attnum > 0 AND c.relkind = 'r' "
00150                       "AND a.attrelid = c.oid "
00151                       "AND a.atttypid IN ('pg_catalog.oid[]'::regtype, "
00152                       " 'pg_catalog.regclass[]'::regtype, "
00153                       " 'pg_catalog.regoper[]'::regtype, "
00154                       " 'pg_catalog.regoperator[]'::regtype, "
00155                       " 'pg_catalog.regproc[]'::regtype, "
00156                       " 'pg_catalog.regprocedure[]'::regtype, "
00157                       " 'pg_catalog.regtype[]'::regtype, "
00158                       " 'pg_catalog.regconfig[]'::regtype, "
00159                       " 'pg_catalog.regdictionary[]'::regtype) "
00160                       "ORDER BY nspname, c.relname, a.attnum"
00161         );
00162 
00163     res = PQexec(conn, sql.data);
00164     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
00165     {
00166         fprintf(stderr, "sql error:  %s\n", PQerrorMessage(conn));
00167         exit(EXIT_FAILURE);
00168     }
00169     fkrel_res = res;
00170 
00171     /*
00172      * For each column and each relation-having-OIDs, look to see if the
00173      * column contains any values matching entries in the relation.
00174      */
00175 
00176     for (fk = 0; fk < PQntuples(fkrel_res); fk++)
00177     {
00178         fk_relname = PQgetvalue(fkrel_res, fk, 0);
00179         fk_nspname = PQgetvalue(fkrel_res, fk, 1);
00180         fk_attname = PQgetvalue(fkrel_res, fk, 2);
00181 
00182         for (pk = 0; pk < PQntuples(pkrel_res); pk++)
00183         {
00184             pk_relname = PQgetvalue(pkrel_res, pk, 0);
00185             pk_nspname = PQgetvalue(pkrel_res, pk, 1);
00186 
00187             printfPQExpBuffer(&sql,
00188                               "SELECT   1 "
00189                               "FROM \"%s\".\"%s\" t1, "
00190                               "\"%s\".\"%s\" t2 "
00191                               "WHERE t2.oid = ANY(t1.\"%s\")"
00192                               "LIMIT 1",
00193                               fk_nspname, fk_relname,
00194                               pk_nspname, pk_relname,
00195                               fk_attname);
00196 
00197             res = PQexec(conn, sql.data);
00198             if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
00199             {
00200                 fprintf(stderr, "sql error:  %s\n", PQerrorMessage(conn));
00201                 exit(EXIT_FAILURE);
00202             }
00203 
00204             if (PQntuples(res) != 0)
00205                 printf("Join %s.%s.%s []=> %s.%s.oid\n",
00206                        fk_nspname, fk_relname, fk_attname,
00207                        pk_nspname, pk_relname);
00208 
00209             PQclear(res);
00210         }
00211     }
00212 
00213     PQclear(fkrel_res);
00214 
00215     PQclear(pkrel_res);
00216 
00217     PQfinish(conn);
00218 
00219     termPQExpBuffer(&sql);
00220 
00221     exit(EXIT_SUCCESS);
00222 }