PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
version.c
Go to the documentation of this file.
1 /*
2  * version.c
3  *
4  * Postgres-version-specific routines
5  *
6  * Copyright (c) 2010-2017, PostgreSQL Global Development Group
7  * src/bin/pg_upgrade/version.c
8  */
9 
10 #include "postgres_fe.h"
11 
12 #include "pg_upgrade.h"
13 #include "fe_utils/string_utils.h"
14 
15 
16 
17 /*
18  * new_9_0_populate_pg_largeobject_metadata()
19  * new >= 9.0, old <= 8.4
20  * 9.0 has a new pg_largeobject permission table
21  */
22 void
24 {
25  int dbnum;
26  FILE *script = NULL;
27  bool found = false;
28  char output_path[MAXPGPATH];
29 
30  prep_status("Checking for large objects");
31 
32  snprintf(output_path, sizeof(output_path), "pg_largeobject.sql");
33 
34  for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
35  {
36  PGresult *res;
37  int i_count;
38  DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
39  PGconn *conn = connectToServer(cluster, active_db->db_name);
40 
41  /* find if there are any large objects */
42  res = executeQueryOrDie(conn,
43  "SELECT count(*) "
44  "FROM pg_catalog.pg_largeobject ");
45 
46  i_count = PQfnumber(res, "count");
47  if (atoi(PQgetvalue(res, 0, i_count)) != 0)
48  {
49  found = true;
50  if (!check_mode)
51  {
52  PQExpBufferData connectbuf;
53 
54  if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
55  pg_fatal("could not open file \"%s\": %s\n", output_path,
56  strerror(errno));
57 
58  initPQExpBuffer(&connectbuf);
59  appendPsqlMetaConnect(&connectbuf, active_db->db_name);
60  fputs(connectbuf.data, script);
61  termPQExpBuffer(&connectbuf);
62 
63  fprintf(script,
64  "SELECT pg_catalog.lo_create(t.loid)\n"
65  "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) AS t;\n");
66  }
67  }
68 
69  PQclear(res);
70  PQfinish(conn);
71  }
72 
73  if (script)
74  fclose(script);
75 
76  if (found)
77  {
78  report_status(PG_WARNING, "warning");
79  if (check_mode)
80  pg_log(PG_WARNING, "\n"
81  "Your installation contains large objects. The new database has an\n"
82  "additional large object permission table. After upgrading, you will be\n"
83  "given a command to populate the pg_largeobject permission table with\n"
84  "default permissions.\n\n");
85  else
86  pg_log(PG_WARNING, "\n"
87  "Your installation contains large objects. The new database has an\n"
88  "additional large object permission table, so default permissions must be\n"
89  "defined for all large objects. The file\n"
90  " %s\n"
91  "when executed by psql by the database superuser will set the default\n"
92  "permissions.\n\n",
93  output_path);
94  }
95  else
96  check_ok();
97 }
98 
99 
100 /*
101  * old_9_3_check_for_line_data_type_usage()
102  * 9.3 -> 9.4
103  * Fully implement the 'line' data type in 9.4, which previously returned
104  * "not enabled" by default and was only functionally enabled with a
105  * compile-time switch; 9.4 "line" has different binary and text
106  * representation formats; checks tables and indexes.
107  */
108 void
110 {
111  int dbnum;
112  FILE *script = NULL;
113  bool found = false;
114  char output_path[MAXPGPATH];
115 
116  prep_status("Checking for invalid \"line\" user columns");
117 
118  snprintf(output_path, sizeof(output_path), "tables_using_line.txt");
119 
120  for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
121  {
122  PGresult *res;
123  bool db_used = false;
124  int ntups;
125  int rowno;
126  int i_nspname,
127  i_relname,
128  i_attname;
129  DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
130  PGconn *conn = connectToServer(cluster, active_db->db_name);
131 
132  res = executeQueryOrDie(conn,
133  "SELECT n.nspname, c.relname, a.attname "
134  "FROM pg_catalog.pg_class c, "
135  " pg_catalog.pg_namespace n, "
136  " pg_catalog.pg_attribute a "
137  "WHERE c.oid = a.attrelid AND "
138  " NOT a.attisdropped AND "
139  " a.atttypid = 'pg_catalog.line'::pg_catalog.regtype AND "
140  " c.relnamespace = n.oid AND "
141  /* exclude possible orphaned temp tables */
142  " n.nspname !~ '^pg_temp_' AND "
143  " n.nspname !~ '^pg_toast_temp_' AND "
144  " n.nspname NOT IN ('pg_catalog', 'information_schema')");
145 
146  ntups = PQntuples(res);
147  i_nspname = PQfnumber(res, "nspname");
148  i_relname = PQfnumber(res, "relname");
149  i_attname = PQfnumber(res, "attname");
150  for (rowno = 0; rowno < ntups; rowno++)
151  {
152  found = true;
153  if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
154  pg_fatal("could not open file \"%s\": %s\n", output_path,
155  strerror(errno));
156  if (!db_used)
157  {
158  fprintf(script, "Database: %s\n", active_db->db_name);
159  db_used = true;
160  }
161  fprintf(script, " %s.%s.%s\n",
162  PQgetvalue(res, rowno, i_nspname),
163  PQgetvalue(res, rowno, i_relname),
164  PQgetvalue(res, rowno, i_attname));
165  }
166 
167  PQclear(res);
168 
169  PQfinish(conn);
170  }
171 
172  if (script)
173  fclose(script);
174 
175  if (found)
176  {
177  pg_log(PG_REPORT, "fatal\n");
178  pg_fatal("Your installation contains the \"line\" data type in user tables. This\n"
179  "data type changed its internal and input/output format between your old\n"
180  "and new clusters so this cluster cannot currently be upgraded. You can\n"
181  "remove the problem tables and restart the upgrade. A list of the problem\n"
182  "columns is in the file:\n"
183  " %s\n\n", output_path);
184  }
185  else
186  check_ok();
187 }
188 
189 
190 /*
191  * old_9_6_check_for_unknown_data_type_usage()
192  * 9.6 -> 10
193  * It's no longer allowed to create tables or views with "unknown"-type
194  * columns. We do not complain about views with such columns, because
195  * they should get silently converted to "text" columns during the DDL
196  * dump and reload; it seems unlikely to be worth making users do that
197  * by hand. However, if there's a table with such a column, the DDL
198  * reload will fail, so we should pre-detect that rather than failing
199  * mid-upgrade. Worse, if there's a matview with such a column, the
200  * DDL reload will silently change it to "text" which won't match the
201  * on-disk storage (which is like "cstring"). So we *must* reject that.
202  * Also check composite types, in case they are used for table columns.
203  * We needn't check indexes, because "unknown" has no opclasses.
204  */
205 void
207 {
208  int dbnum;
209  FILE *script = NULL;
210  bool found = false;
211  char output_path[MAXPGPATH];
212 
213  prep_status("Checking for invalid \"unknown\" user columns");
214 
215  snprintf(output_path, sizeof(output_path), "tables_using_unknown.txt");
216 
217  for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
218  {
219  PGresult *res;
220  bool db_used = false;
221  int ntups;
222  int rowno;
223  int i_nspname,
224  i_relname,
225  i_attname;
226  DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
227  PGconn *conn = connectToServer(cluster, active_db->db_name);
228 
229  res = executeQueryOrDie(conn,
230  "SELECT n.nspname, c.relname, a.attname "
231  "FROM pg_catalog.pg_class c, "
232  " pg_catalog.pg_namespace n, "
233  " pg_catalog.pg_attribute a "
234  "WHERE c.oid = a.attrelid AND "
235  " NOT a.attisdropped AND "
236  " a.atttypid = 'pg_catalog.unknown'::pg_catalog.regtype AND "
237  " c.relkind IN ('r', 'c', 'm') AND "
238  " c.relnamespace = n.oid AND "
239  /* exclude possible orphaned temp tables */
240  " n.nspname !~ '^pg_temp_' AND "
241  " n.nspname !~ '^pg_toast_temp_' AND "
242  " n.nspname NOT IN ('pg_catalog', 'information_schema')");
243 
244  ntups = PQntuples(res);
245  i_nspname = PQfnumber(res, "nspname");
246  i_relname = PQfnumber(res, "relname");
247  i_attname = PQfnumber(res, "attname");
248  for (rowno = 0; rowno < ntups; rowno++)
249  {
250  found = true;
251  if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
252  pg_fatal("could not open file \"%s\": %s\n", output_path,
253  strerror(errno));
254  if (!db_used)
255  {
256  fprintf(script, "Database: %s\n", active_db->db_name);
257  db_used = true;
258  }
259  fprintf(script, " %s.%s.%s\n",
260  PQgetvalue(res, rowno, i_nspname),
261  PQgetvalue(res, rowno, i_relname),
262  PQgetvalue(res, rowno, i_attname));
263  }
264 
265  PQclear(res);
266 
267  PQfinish(conn);
268  }
269 
270  if (script)
271  fclose(script);
272 
273  if (found)
274  {
275  pg_log(PG_REPORT, "fatal\n");
276  pg_fatal("Your installation contains the \"unknown\" data type in user tables. This\n"
277  "data type is no longer allowed in tables, so this cluster cannot currently\n"
278  "be upgraded. You can remove the problem tables and restart the upgrade.\n"
279  "A list of the problem columns is in the file:\n"
280  " %s\n\n", output_path);
281  }
282  else
283  check_ok();
284 }
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3067
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
void old_9_6_check_for_unknown_data_type_usage(ClusterInfo *cluster)
Definition: version.c:206
PGresult * executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3516
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
FILE * fopen_priv(const char *path, const char *mode)
Definition: file.c:321
void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname)
Definition: string_utils.c:581
PGconn * conn
Definition: streamutil.c:42
#define MAXPGPATH
void prep_status(const char *fmt,...) pg_attribute_printf(1
void cluster(ClusterStmt *stmt, bool isTopLevel)
Definition: cluster.c:106
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
static void check_ok(void)
Definition: initdb.c:1987
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
int PQfnumber(const PGresult *res, const char *field_name)
Definition: fe-exec.c:2781
void PQclear(PGresult *res)
Definition: fe-exec.c:650
DbInfoArr dbarr
Definition: pg_upgrade.h:265
#define NULL
Definition: c.h:226
const char * strerror(int errnum)
Definition: strerror.c:19
void report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2
char * db_name
Definition: pg_upgrade.h:187
void new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
Definition: version.c:23
DbInfo * dbs
Definition: pg_upgrade.h:198
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89
void old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
Definition: version.c:109