4 * Postgres-version-specific routines
6 * Copyright (c) 2010-2013, PostgreSQL Global Development Group
7 * contrib/pg_upgrade/version_old_8_3.c
10 #include "postgres_fe.h"
12 #include "pg_upgrade.h"
14 #include "access/transam.h"
18 * old_8_3_check_for_name_data_type_usage()
20 * Alignment for the 'name' data type changed to 'char' in 8.4;
21 * checks tables and indexes.
24 old_8_3_check_for_name_data_type_usage(ClusterInfo *cluster)
29 char output_path[MAXPGPATH];
31 prep_status("Checking for invalid \"name\" user columns");
33 snprintf(output_path, sizeof(output_path), "tables_using_name.txt");
35 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
44 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
45 PGconn *conn = connectToServer(cluster, active_db->db_name);
48 * With a smaller alignment in 8.4, 'name' cannot be used in a
49 * non-pg_catalog table, except as the first column. (We could tighten
50 * that condition with enough analysis, but it seems not worth the
53 res = executeQueryOrDie(conn,
54 "SELECT n.nspname, c.relname, a.attname "
55 "FROM pg_catalog.pg_class c, "
56 " pg_catalog.pg_namespace n, "
57 " pg_catalog.pg_attribute a "
58 "WHERE c.oid = a.attrelid AND "
60 " NOT a.attisdropped AND "
61 " a.atttypid = 'pg_catalog.name'::pg_catalog.regtype AND "
62 " c.relnamespace = n.oid AND "
63 /* exclude possible orphaned temp tables */
64 " n.nspname !~ '^pg_temp_' AND "
65 " n.nspname !~ '^pg_toast_temp_' AND "
66 " n.nspname NOT IN ('pg_catalog', 'information_schema')");
68 ntups = PQntuples(res);
69 i_nspname = PQfnumber(res, "nspname");
70 i_relname = PQfnumber(res, "relname");
71 i_attname = PQfnumber(res, "attname");
72 for (rowno = 0; rowno < ntups; rowno++)
75 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
76 pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
79 fprintf(script, "Database: %s\n", active_db->db_name);
82 fprintf(script, " %s.%s.%s\n",
83 PQgetvalue(res, rowno, i_nspname),
84 PQgetvalue(res, rowno, i_relname),
85 PQgetvalue(res, rowno, i_attname));
98 pg_log(PG_REPORT, "fatal\n");
99 pg_fatal("Your installation contains the \"name\" data type in user tables. This\n"
100 "data type changed its internal alignment between your old and new\n"
101 "clusters so this cluster cannot currently be upgraded. You can remove\n"
102 "the problem tables and restart the upgrade. A list of the problem\n"
103 "columns is in the file:\n"
104 " %s\n\n", output_path);
112 * old_8_3_check_for_tsquery_usage()
114 * A new 'prefix' field was added to the 'tsquery' data type in 8.4
115 * so upgrading of such fields is impossible.
118 old_8_3_check_for_tsquery_usage(ClusterInfo *cluster)
123 char output_path[MAXPGPATH];
125 prep_status("Checking for tsquery user columns");
127 snprintf(output_path, sizeof(output_path), "tables_using_tsquery.txt");
129 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
132 bool db_used = false;
138 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
139 PGconn *conn = connectToServer(cluster, active_db->db_name);
141 /* Find any user-defined tsquery columns */
142 res = executeQueryOrDie(conn,
143 "SELECT n.nspname, c.relname, a.attname "
144 "FROM pg_catalog.pg_class c, "
145 " pg_catalog.pg_namespace n, "
146 " pg_catalog.pg_attribute a "
147 /* materialized views didn't exist in 8.3, so no need to check 'm' */
148 "WHERE c.relkind = 'r' AND "
149 " c.oid = a.attrelid AND "
150 " NOT a.attisdropped AND "
151 " a.atttypid = 'pg_catalog.tsquery'::pg_catalog.regtype AND "
152 " c.relnamespace = n.oid AND "
153 /* exclude possible orphaned temp tables */
154 " n.nspname !~ '^pg_temp_' AND "
155 " n.nspname !~ '^pg_toast_temp_' AND "
156 " n.nspname NOT IN ('pg_catalog', 'information_schema')");
158 ntups = PQntuples(res);
159 i_nspname = PQfnumber(res, "nspname");
160 i_relname = PQfnumber(res, "relname");
161 i_attname = PQfnumber(res, "attname");
162 for (rowno = 0; rowno < ntups; rowno++)
165 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
166 pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
169 fprintf(script, "Database: %s\n", active_db->db_name);
172 fprintf(script, " %s.%s.%s\n",
173 PQgetvalue(res, rowno, i_nspname),
174 PQgetvalue(res, rowno, i_relname),
175 PQgetvalue(res, rowno, i_attname));
188 pg_log(PG_REPORT, "fatal\n");
189 pg_fatal("Your installation contains the \"tsquery\" data type. This data type\n"
190 "added a new internal field between your old and new clusters so this\n"
191 "cluster cannot currently be upgraded. You can remove the problem\n"
192 "columns and restart the upgrade. A list of the problem columns is in the\n"
194 " %s\n\n", output_path);
202 * old_8_3_check_ltree_usage()
204 * The internal ltree structure was changed in 8.4 so upgrading is impossible.
207 old_8_3_check_ltree_usage(ClusterInfo *cluster)
212 char output_path[MAXPGPATH];
214 prep_status("Checking for contrib/ltree");
216 snprintf(output_path, sizeof(output_path), "contrib_ltree.txt");
218 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
221 bool db_used = false;
226 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
227 PGconn *conn = connectToServer(cluster, active_db->db_name);
229 /* Find any functions coming from contrib/ltree */
230 res = executeQueryOrDie(conn,
231 "SELECT n.nspname, p.proname "
232 "FROM pg_catalog.pg_proc p, "
233 " pg_catalog.pg_namespace n "
234 "WHERE p.pronamespace = n.oid AND "
235 " p.probin = '$libdir/ltree'");
237 ntups = PQntuples(res);
238 i_nspname = PQfnumber(res, "nspname");
239 i_proname = PQfnumber(res, "proname");
240 for (rowno = 0; rowno < ntups; rowno++)
243 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
244 pg_fatal("Could not open file \"%s\": %s\n",
245 output_path, getErrorText(errno));
248 fprintf(script, "Database: %s\n", active_db->db_name);
251 fprintf(script, " %s.%s\n",
252 PQgetvalue(res, rowno, i_nspname),
253 PQgetvalue(res, rowno, i_proname));
266 pg_log(PG_REPORT, "fatal\n");
267 pg_fatal("Your installation contains the \"ltree\" data type. This data type\n"
268 "changed its internal storage format between your old and new clusters so this\n"
269 "cluster cannot currently be upgraded. You can manually upgrade databases\n"
270 "that use \"contrib/ltree\" facilities and remove \"contrib/ltree\" from the old\n"
271 "cluster and restart the upgrade. A list of the problem functions is in the\n"
273 " %s\n\n", output_path);
281 * old_8_3_rebuild_tsvector_tables()
283 * 8.3 sorts lexemes by its length and if lengths are the same then it uses
284 * alphabetic order; 8.4 sorts lexemes in lexicographical order, e.g.
286 * => SELECT 'c bb aaa'::tsvector;
289 * 'aaa' 'bb' 'c' -- 8.4
290 * 'c' 'bb' 'aaa' -- 8.3
293 old_8_3_rebuild_tsvector_tables(ClusterInfo *cluster, bool check_mode)
298 char output_path[MAXPGPATH];
300 prep_status("Checking for tsvector user columns");
302 snprintf(output_path, sizeof(output_path), "rebuild_tsvector_tables.sql");
304 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
307 bool db_used = false;
308 char nspname[NAMEDATALEN] = "",
309 relname[NAMEDATALEN] = "";
315 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
316 PGconn *conn = connectToServer(cluster, active_db->db_name);
318 /* Find any user-defined tsvector columns */
319 res = executeQueryOrDie(conn,
320 "SELECT n.nspname, c.relname, a.attname "
321 "FROM pg_catalog.pg_class c, "
322 " pg_catalog.pg_namespace n, "
323 " pg_catalog.pg_attribute a "
324 /* materialized views didn't exist in 8.3, so no need to check 'm' */
325 "WHERE c.relkind = 'r' AND "
326 " c.oid = a.attrelid AND "
327 " NOT a.attisdropped AND "
328 " a.atttypid = 'pg_catalog.tsvector'::pg_catalog.regtype AND "
329 " c.relnamespace = n.oid AND "
330 /* exclude possible orphaned temp tables */
331 " n.nspname !~ '^pg_temp_' AND "
332 " n.nspname !~ '^pg_toast_temp_' AND "
333 " n.nspname NOT IN ('pg_catalog', 'information_schema')");
336 * This macro is used below to avoid reindexing indexes already rebuilt
337 * because of tsvector columns.
339 #define SKIP_TSVECTOR_TABLES \
340 "i.indrelid NOT IN ( " \
341 "SELECT DISTINCT c.oid " \
342 "FROM pg_catalog.pg_class c, " \
343 " pg_catalog.pg_namespace n, " \
344 " pg_catalog.pg_attribute a " \
345 /* materialized views didn't exist in 8.3, so no need to check 'm' */ \
346 "WHERE c.relkind = 'r' AND " \
347 " c.oid = a.attrelid AND " \
348 " NOT a.attisdropped AND " \
349 " a.atttypid = 'pg_catalog.tsvector'::pg_catalog.regtype AND " \
350 " c.relnamespace = n.oid AND " \
351 " n.nspname !~ '^pg_' AND " \
352 " n.nspname != 'information_schema') "
354 ntups = PQntuples(res);
355 i_nspname = PQfnumber(res, "nspname");
356 i_relname = PQfnumber(res, "relname");
357 i_attname = PQfnumber(res, "attname");
358 for (rowno = 0; rowno < ntups; rowno++)
363 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
364 pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
367 fprintf(script, "\\connect %s\n\n",
368 quote_identifier(active_db->db_name));
372 /* Rebuild all tsvector collumns with one ALTER TABLE command */
373 if (strcmp(PQgetvalue(res, rowno, i_nspname), nspname) != 0 ||
374 strcmp(PQgetvalue(res, rowno, i_relname), relname) != 0)
376 if (strlen(nspname) != 0 || strlen(relname) != 0)
377 fprintf(script, ";\n\n");
378 fprintf(script, "ALTER TABLE %s.%s\n",
379 quote_identifier(PQgetvalue(res, rowno, i_nspname)),
380 quote_identifier(PQgetvalue(res, rowno, i_relname)));
383 fprintf(script, ",\n");
384 strlcpy(nspname, PQgetvalue(res, rowno, i_nspname), sizeof(nspname));
385 strlcpy(relname, PQgetvalue(res, rowno, i_relname), sizeof(relname));
387 fprintf(script, "ALTER COLUMN %s "
388 /* This could have been a custom conversion function call. */
389 "TYPE pg_catalog.tsvector USING %s::pg_catalog.text::pg_catalog.tsvector",
390 quote_identifier(PQgetvalue(res, rowno, i_attname)),
391 quote_identifier(PQgetvalue(res, rowno, i_attname)));
394 if (strlen(nspname) != 0 || strlen(relname) != 0)
395 fprintf(script, ";\n\n");
399 /* XXX Mark tables as not accessible somehow */
409 report_status(PG_WARNING, "warning");
411 pg_log(PG_WARNING, "\n"
412 "Your installation contains tsvector columns. The tsvector internal\n"
413 "storage format changed between your old and new clusters so the tables\n"
414 "must be rebuilt. After upgrading, you will be given instructions.\n\n");
416 pg_log(PG_WARNING, "\n"
417 "Your installation contains tsvector columns. The tsvector internal\n"
418 "storage format changed between your old and new clusters so the tables\n"
419 "must be rebuilt. The file:\n"
421 "when executed by psql by the database superuser will rebuild all tables\n"
422 "with tsvector columns.\n\n",
431 * old_8_3_invalidate_hash_gin_indexes()
433 * Hash and GIN index binary format changed from 8.3->8.4
436 old_8_3_invalidate_hash_gin_indexes(ClusterInfo *cluster, bool check_mode)
441 char output_path[MAXPGPATH];
443 prep_status("Checking for hash and GIN indexes");
445 snprintf(output_path, sizeof(output_path), "reindex_hash_and_gin.sql");
447 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
450 bool db_used = false;
455 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
456 PGconn *conn = connectToServer(cluster, active_db->db_name);
458 /* find hash and gin indexes */
459 res = executeQueryOrDie(conn,
460 "SELECT n.nspname, c.relname "
461 "FROM pg_catalog.pg_class c, "
462 " pg_catalog.pg_index i, "
463 " pg_catalog.pg_am a, "
464 " pg_catalog.pg_namespace n "
465 "WHERE i.indexrelid = c.oid AND "
466 " c.relam = a.oid AND "
467 " c.relnamespace = n.oid AND "
468 " a.amname IN ('hash', 'gin') AND "
469 SKIP_TSVECTOR_TABLES);
471 ntups = PQntuples(res);
472 i_nspname = PQfnumber(res, "nspname");
473 i_relname = PQfnumber(res, "relname");
474 for (rowno = 0; rowno < ntups; rowno++)
479 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
480 pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
483 fprintf(script, "\\connect %s\n",
484 quote_identifier(active_db->db_name));
487 fprintf(script, "REINDEX INDEX %s.%s;\n",
488 quote_identifier(PQgetvalue(res, rowno, i_nspname)),
489 quote_identifier(PQgetvalue(res, rowno, i_relname)));
495 if (!check_mode && found)
496 /* mark hash and gin indexes as invalid */
497 PQclear(executeQueryOrDie(conn,
498 "UPDATE pg_catalog.pg_index i "
499 "SET indisvalid = false "
500 "FROM pg_catalog.pg_class c, "
501 " pg_catalog.pg_am a, "
502 " pg_catalog.pg_namespace n "
503 "WHERE i.indexrelid = c.oid AND "
504 " c.relam = a.oid AND "
505 " c.relnamespace = n.oid AND "
506 " a.amname IN ('hash', 'gin')"));
516 report_status(PG_WARNING, "warning");
518 pg_log(PG_WARNING, "\n"
519 "Your installation contains hash and/or GIN indexes. These indexes have\n"
520 "different internal formats between your old and new clusters, so they\n"
521 "must be reindexed with the REINDEX command. After upgrading, you will\n"
522 "be given REINDEX instructions.\n\n");
524 pg_log(PG_WARNING, "\n"
525 "Your installation contains hash and/or GIN indexes. These indexes have\n"
526 "different internal formats between your old and new clusters, so they\n"
527 "must be reindexed with the REINDEX command. The file:\n"
529 "when executed by psql by the database superuser will recreate all invalid\n"
530 "indexes; until then, none of these indexes will be used.\n\n",
539 * old_8_3_invalidate_bpchar_pattern_ops_indexes()
541 * 8.4 bpchar_pattern_ops no longer sorts based on trailing spaces
544 old_8_3_invalidate_bpchar_pattern_ops_indexes(ClusterInfo *cluster,
550 char output_path[MAXPGPATH];
552 prep_status("Checking for bpchar_pattern_ops indexes");
554 snprintf(output_path, sizeof(output_path), "reindex_bpchar_ops.sql");
556 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
559 bool db_used = false;
564 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
565 PGconn *conn = connectToServer(cluster, active_db->db_name);
567 /* find bpchar_pattern_ops indexes */
570 * Do only non-hash, non-gin indexees; we already invalidated them
571 * above; no need to reindex twice
573 res = executeQueryOrDie(conn,
574 "SELECT n.nspname, c.relname "
575 "FROM pg_catalog.pg_index i, "
576 " pg_catalog.pg_class c, "
577 " pg_catalog.pg_namespace n "
578 "WHERE indexrelid = c.oid AND "
579 " c.relnamespace = n.oid AND "
582 " FROM pg_catalog.pg_opclass o, "
583 " pg_catalog.pg_am a"
584 " WHERE a.amname NOT IN ('hash', 'gin') AND "
585 " a.oid = o.opcmethod AND "
586 " o.opcname = 'bpchar_pattern_ops') "
587 " = ANY (i.indclass) AND "
588 SKIP_TSVECTOR_TABLES);
590 ntups = PQntuples(res);
591 i_nspname = PQfnumber(res, "nspname");
592 i_relname = PQfnumber(res, "relname");
593 for (rowno = 0; rowno < ntups; rowno++)
598 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
599 pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
602 fprintf(script, "\\connect %s\n",
603 quote_identifier(active_db->db_name));
606 fprintf(script, "REINDEX INDEX %s.%s;\n",
607 quote_identifier(PQgetvalue(res, rowno, i_nspname)),
608 quote_identifier(PQgetvalue(res, rowno, i_relname)));
614 if (!check_mode && found)
615 /* mark bpchar_pattern_ops indexes as invalid */
616 PQclear(executeQueryOrDie(conn,
617 "UPDATE pg_catalog.pg_index i "
618 "SET indisvalid = false "
619 "FROM pg_catalog.pg_class c, "
620 " pg_catalog.pg_namespace n "
621 "WHERE indexrelid = c.oid AND "
622 " c.relnamespace = n.oid AND "
625 " FROM pg_catalog.pg_opclass o, "
626 " pg_catalog.pg_am a"
627 " WHERE a.amname NOT IN ('hash', 'gin') AND "
628 " a.oid = o.opcmethod AND "
629 " o.opcname = 'bpchar_pattern_ops') "
630 " = ANY (i.indclass)"));
640 report_status(PG_WARNING, "warning");
642 pg_log(PG_WARNING, "\n"
643 "Your installation contains indexes using \"bpchar_pattern_ops\". These\n"
644 "indexes have different internal formats between your old and new clusters\n"
645 "so they must be reindexed with the REINDEX command. After upgrading, you\n"
646 "will be given REINDEX instructions.\n\n");
648 pg_log(PG_WARNING, "\n"
649 "Your installation contains indexes using \"bpchar_pattern_ops\". These\n"
650 "indexes have different internal formats between your old and new clusters\n"
651 "so they must be reindexed with the REINDEX command. The file:\n"
653 "when executed by psql by the database superuser will recreate all invalid\n"
654 "indexes; until then, none of these indexes will be used.\n\n",
663 * old_8_3_create_sequence_script()
665 * 8.4 added the column "start_value" to all sequences. For this reason,
666 * we don't transfer sequence files but instead use the CREATE SEQUENCE
667 * command from the schema dump, and use setval() to restore the sequence
668 * value and 'is_called' from the old database. This is safe to run
669 * by pg_upgrade because sequence files are not transferred from the old
670 * server, even in link mode.
673 old_8_3_create_sequence_script(ClusterInfo *cluster)
680 output_path = pg_strdup("adjust_sequences.sql");
682 prep_status("Creating script to adjust sequences");
684 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
687 bool db_used = false;
692 DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
693 PGconn *conn = connectToServer(cluster, active_db->db_name);
695 /* Find any sequences */
696 res = executeQueryOrDie(conn,
697 "SELECT n.nspname, c.relname "
698 "FROM pg_catalog.pg_class c, "
699 " pg_catalog.pg_namespace n "
700 "WHERE c.relkind = 'S' AND "
701 " c.relnamespace = n.oid AND "
702 /* exclude possible orphaned temp tables */
703 " n.nspname !~ '^pg_temp_' AND "
704 " n.nspname !~ '^pg_toast_temp_' AND "
705 " n.nspname NOT IN ('pg_catalog', 'information_schema')");
707 ntups = PQntuples(res);
708 i_nspname = PQfnumber(res, "nspname");
709 i_relname = PQfnumber(res, "relname");
710 for (rowno = 0; rowno < ntups; rowno++)
715 const char *nspname = PQgetvalue(res, rowno, i_nspname);
716 const char *relname = PQgetvalue(res, rowno, i_relname);
720 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
721 pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
724 fprintf(script, "\\connect %s\n\n",
725 quote_identifier(active_db->db_name));
729 /* Find the desired sequence */
730 seq_res = executeQueryOrDie(conn,
731 "SELECT s.last_value, s.is_called "
733 quote_identifier(nspname),
734 quote_identifier(relname));
736 assert(PQntuples(seq_res) == 1);
737 i_last_value = PQfnumber(seq_res, "last_value");
738 i_is_called = PQfnumber(seq_res, "is_called");
740 fprintf(script, "SELECT setval('%s.%s', %s, '%s');\n",
741 quote_identifier(nspname), quote_identifier(relname),
742 PQgetvalue(seq_res, 0, i_last_value), PQgetvalue(seq_res, 0, i_is_called));
746 fprintf(script, "\n");
762 pg_free(output_path);