mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-23 21:17:18 +02:00
This only affects upgrades from 8.3 currently, and is harmless as the child just generates an error in the script, but we should get it right in case we ever need this for more complex uses. Per report from Peter Eisentraut
770 lines
22 KiB
C
770 lines
22 KiB
C
/*
|
|
* version.c
|
|
*
|
|
* Postgres-version-specific routines
|
|
*
|
|
* Copyright (c) 2010-2013, PostgreSQL Global Development Group
|
|
* contrib/pg_upgrade/version_old_8_3.c
|
|
*/
|
|
|
|
#include "postgres_fe.h"
|
|
|
|
#include "pg_upgrade.h"
|
|
|
|
#include "access/transam.h"
|
|
|
|
|
|
/*
|
|
* old_8_3_check_for_name_data_type_usage()
|
|
* 8.3 -> 8.4
|
|
* Alignment for the 'name' data type changed to 'char' in 8.4;
|
|
* checks tables and indexes.
|
|
*/
|
|
void
|
|
old_8_3_check_for_name_data_type_usage(ClusterInfo *cluster)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char output_path[MAXPGPATH];
|
|
|
|
prep_status("Checking for invalid \"name\" user columns");
|
|
|
|
snprintf(output_path, sizeof(output_path), "tables_using_name.txt");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_relname,
|
|
i_attname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/*
|
|
* With a smaller alignment in 8.4, 'name' cannot be used in a
|
|
* non-pg_catalog table, except as the first column. (We could tighten
|
|
* that condition with enough analysis, but it seems not worth the
|
|
* trouble.)
|
|
*/
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, c.relname, a.attname "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_namespace n, "
|
|
" pg_catalog.pg_attribute a "
|
|
"WHERE c.oid = a.attrelid AND "
|
|
" a.attnum > 1 AND "
|
|
" NOT a.attisdropped AND "
|
|
" a.atttypid = 'pg_catalog.name'::pg_catalog.regtype AND "
|
|
" c.relnamespace = n.oid AND "
|
|
/* exclude possible orphaned temp tables */
|
|
" n.nspname !~ '^pg_temp_' AND "
|
|
" n.nspname !~ '^pg_toast_temp_' AND "
|
|
" n.nspname NOT IN ('pg_catalog', 'information_schema')");
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_relname = PQfnumber(res, "relname");
|
|
i_attname = PQfnumber(res, "attname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
found = true;
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "Database: %s\n", active_db->db_name);
|
|
db_used = true;
|
|
}
|
|
fprintf(script, " %s.%s.%s\n",
|
|
PQgetvalue(res, rowno, i_nspname),
|
|
PQgetvalue(res, rowno, i_relname),
|
|
PQgetvalue(res, rowno, i_attname));
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
if (found)
|
|
{
|
|
pg_log(PG_REPORT, "fatal\n");
|
|
pg_fatal("Your installation contains the \"name\" data type in user tables. This\n"
|
|
"data type changed its internal alignment between your old and new\n"
|
|
"clusters so this cluster cannot currently be upgraded. You can remove\n"
|
|
"the problem tables and restart the upgrade. A list of the problem\n"
|
|
"columns is in the file:\n"
|
|
" %s\n\n", output_path);
|
|
}
|
|
else
|
|
check_ok();
|
|
}
|
|
|
|
|
|
/*
|
|
* old_8_3_check_for_tsquery_usage()
|
|
* 8.3 -> 8.4
|
|
* A new 'prefix' field was added to the 'tsquery' data type in 8.4
|
|
* so upgrading of such fields is impossible.
|
|
*/
|
|
void
|
|
old_8_3_check_for_tsquery_usage(ClusterInfo *cluster)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char output_path[MAXPGPATH];
|
|
|
|
prep_status("Checking for tsquery user columns");
|
|
|
|
snprintf(output_path, sizeof(output_path), "tables_using_tsquery.txt");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_relname,
|
|
i_attname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/* Find any user-defined tsquery columns */
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, c.relname, a.attname "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_namespace n, "
|
|
" pg_catalog.pg_attribute a "
|
|
/* materialized views didn't exist in 8.3, so no need to check 'm' */
|
|
"WHERE c.relkind = 'r' AND "
|
|
" c.oid = a.attrelid AND "
|
|
" NOT a.attisdropped AND "
|
|
" a.atttypid = 'pg_catalog.tsquery'::pg_catalog.regtype AND "
|
|
" c.relnamespace = n.oid AND "
|
|
/* exclude possible orphaned temp tables */
|
|
" n.nspname !~ '^pg_temp_' AND "
|
|
" n.nspname !~ '^pg_toast_temp_' AND "
|
|
" n.nspname NOT IN ('pg_catalog', 'information_schema')");
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_relname = PQfnumber(res, "relname");
|
|
i_attname = PQfnumber(res, "attname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
found = true;
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "Database: %s\n", active_db->db_name);
|
|
db_used = true;
|
|
}
|
|
fprintf(script, " %s.%s.%s\n",
|
|
PQgetvalue(res, rowno, i_nspname),
|
|
PQgetvalue(res, rowno, i_relname),
|
|
PQgetvalue(res, rowno, i_attname));
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
if (found)
|
|
{
|
|
pg_log(PG_REPORT, "fatal\n");
|
|
pg_fatal("Your installation contains the \"tsquery\" data type. This data type\n"
|
|
"added a new internal field between your old and new clusters so this\n"
|
|
"cluster cannot currently be upgraded. You can remove the problem\n"
|
|
"columns and restart the upgrade. A list of the problem columns is in the\n"
|
|
"file:\n"
|
|
" %s\n\n", output_path);
|
|
}
|
|
else
|
|
check_ok();
|
|
}
|
|
|
|
|
|
/*
|
|
* old_8_3_check_ltree_usage()
|
|
* 8.3 -> 8.4
|
|
* The internal ltree structure was changed in 8.4 so upgrading is impossible.
|
|
*/
|
|
void
|
|
old_8_3_check_ltree_usage(ClusterInfo *cluster)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char output_path[MAXPGPATH];
|
|
|
|
prep_status("Checking for contrib/ltree");
|
|
|
|
snprintf(output_path, sizeof(output_path), "contrib_ltree.txt");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_proname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/* Find any functions coming from contrib/ltree */
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, p.proname "
|
|
"FROM pg_catalog.pg_proc p, "
|
|
" pg_catalog.pg_namespace n "
|
|
"WHERE p.pronamespace = n.oid AND "
|
|
" p.probin = '$libdir/ltree'");
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_proname = PQfnumber(res, "proname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
found = true;
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("Could not open file \"%s\": %s\n",
|
|
output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "Database: %s\n", active_db->db_name);
|
|
db_used = true;
|
|
}
|
|
fprintf(script, " %s.%s\n",
|
|
PQgetvalue(res, rowno, i_nspname),
|
|
PQgetvalue(res, rowno, i_proname));
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
if (found)
|
|
{
|
|
pg_log(PG_REPORT, "fatal\n");
|
|
pg_fatal("Your installation contains the \"ltree\" data type. This data type\n"
|
|
"changed its internal storage format between your old and new clusters so this\n"
|
|
"cluster cannot currently be upgraded. You can manually upgrade databases\n"
|
|
"that use \"contrib/ltree\" facilities and remove \"contrib/ltree\" from the old\n"
|
|
"cluster and restart the upgrade. A list of the problem functions is in the\n"
|
|
"file:\n"
|
|
" %s\n\n", output_path);
|
|
}
|
|
else
|
|
check_ok();
|
|
}
|
|
|
|
|
|
/*
|
|
* old_8_3_rebuild_tsvector_tables()
|
|
* 8.3 -> 8.4
|
|
* 8.3 sorts lexemes by its length and if lengths are the same then it uses
|
|
* alphabetic order; 8.4 sorts lexemes in lexicographical order, e.g.
|
|
*
|
|
* => SELECT 'c bb aaa'::tsvector;
|
|
* tsvector
|
|
* ----------------
|
|
* 'aaa' 'bb' 'c' -- 8.4
|
|
* 'c' 'bb' 'aaa' -- 8.3
|
|
*/
|
|
void
|
|
old_8_3_rebuild_tsvector_tables(ClusterInfo *cluster, bool check_mode)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char output_path[MAXPGPATH];
|
|
|
|
prep_status("Checking for tsvector user columns");
|
|
|
|
snprintf(output_path, sizeof(output_path), "rebuild_tsvector_tables.sql");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
char nspname[NAMEDATALEN] = "",
|
|
relname[NAMEDATALEN] = "";
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_relname,
|
|
i_attname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/* Find any user-defined tsvector columns */
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, c.relname, a.attname "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_namespace n, "
|
|
" pg_catalog.pg_attribute a "
|
|
/* materialized views didn't exist in 8.3, so no need to check 'm' */
|
|
"WHERE c.relkind = 'r' AND "
|
|
" c.oid = a.attrelid AND "
|
|
" NOT a.attisdropped AND "
|
|
/* child attribute changes are processed by the parent */
|
|
" a.attinhcount = 0 AND "
|
|
" a.atttypid = 'pg_catalog.tsvector'::pg_catalog.regtype AND "
|
|
" c.relnamespace = n.oid AND "
|
|
/* exclude possible orphaned temp tables */
|
|
" n.nspname !~ '^pg_temp_' AND "
|
|
" n.nspname !~ '^pg_toast_temp_' AND "
|
|
" n.nspname NOT IN ('pg_catalog', 'information_schema')");
|
|
|
|
/*
|
|
* This macro is used below to avoid reindexing indexes already rebuilt
|
|
* because of tsvector columns.
|
|
*/
|
|
#define SKIP_TSVECTOR_TABLES \
|
|
"i.indrelid NOT IN ( " \
|
|
"SELECT DISTINCT c.oid " \
|
|
"FROM pg_catalog.pg_class c, " \
|
|
" pg_catalog.pg_namespace n, " \
|
|
" pg_catalog.pg_attribute a " \
|
|
/* materialized views didn't exist in 8.3, so no need to check 'm' */ \
|
|
"WHERE c.relkind = 'r' AND " \
|
|
" c.oid = a.attrelid AND " \
|
|
" NOT a.attisdropped AND " \
|
|
/* child attribute changes are processed by the parent */ \
|
|
" a.attinhcount = 0 AND " \
|
|
" a.atttypid = 'pg_catalog.tsvector'::pg_catalog.regtype AND " \
|
|
" c.relnamespace = n.oid AND " \
|
|
" n.nspname !~ '^pg_' AND " \
|
|
" n.nspname != 'information_schema') "
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_relname = PQfnumber(res, "relname");
|
|
i_attname = PQfnumber(res, "attname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
found = true;
|
|
if (!check_mode)
|
|
{
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "\\connect %s\n\n",
|
|
quote_identifier(active_db->db_name));
|
|
db_used = true;
|
|
}
|
|
|
|
/* Rebuild all tsvector collumns with one ALTER TABLE command */
|
|
if (strcmp(PQgetvalue(res, rowno, i_nspname), nspname) != 0 ||
|
|
strcmp(PQgetvalue(res, rowno, i_relname), relname) != 0)
|
|
{
|
|
if (strlen(nspname) != 0 || strlen(relname) != 0)
|
|
fprintf(script, ";\n\n");
|
|
fprintf(script, "ALTER TABLE %s.%s\n",
|
|
quote_identifier(PQgetvalue(res, rowno, i_nspname)),
|
|
quote_identifier(PQgetvalue(res, rowno, i_relname)));
|
|
}
|
|
else
|
|
fprintf(script, ",\n");
|
|
strlcpy(nspname, PQgetvalue(res, rowno, i_nspname), sizeof(nspname));
|
|
strlcpy(relname, PQgetvalue(res, rowno, i_relname), sizeof(relname));
|
|
|
|
fprintf(script, "ALTER COLUMN %s "
|
|
/* This could have been a custom conversion function call. */
|
|
"TYPE pg_catalog.tsvector USING %s::pg_catalog.text::pg_catalog.tsvector",
|
|
quote_identifier(PQgetvalue(res, rowno, i_attname)),
|
|
quote_identifier(PQgetvalue(res, rowno, i_attname)));
|
|
}
|
|
}
|
|
if (strlen(nspname) != 0 || strlen(relname) != 0)
|
|
fprintf(script, ";\n\n");
|
|
|
|
PQclear(res);
|
|
|
|
/* XXX Mark tables as not accessible somehow */
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
if (found)
|
|
{
|
|
report_status(PG_WARNING, "warning");
|
|
if (check_mode)
|
|
pg_log(PG_WARNING, "\n"
|
|
"Your installation contains tsvector columns. The tsvector internal\n"
|
|
"storage format changed between your old and new clusters so the tables\n"
|
|
"must be rebuilt. After upgrading, you will be given instructions.\n\n");
|
|
else
|
|
pg_log(PG_WARNING, "\n"
|
|
"Your installation contains tsvector columns. The tsvector internal\n"
|
|
"storage format changed between your old and new clusters so the tables\n"
|
|
"must be rebuilt. The file:\n"
|
|
" %s\n"
|
|
"when executed by psql by the database superuser will rebuild all tables\n"
|
|
"with tsvector columns.\n\n",
|
|
output_path);
|
|
}
|
|
else
|
|
check_ok();
|
|
}
|
|
|
|
|
|
/*
|
|
* old_8_3_invalidate_hash_gin_indexes()
|
|
* 8.3 -> 8.4
|
|
* Hash and GIN index binary format changed from 8.3->8.4
|
|
*/
|
|
void
|
|
old_8_3_invalidate_hash_gin_indexes(ClusterInfo *cluster, bool check_mode)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char output_path[MAXPGPATH];
|
|
|
|
prep_status("Checking for hash and GIN indexes");
|
|
|
|
snprintf(output_path, sizeof(output_path), "reindex_hash_and_gin.sql");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_relname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/* find hash and gin indexes */
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, c.relname "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_index i, "
|
|
" pg_catalog.pg_am a, "
|
|
" pg_catalog.pg_namespace n "
|
|
"WHERE i.indexrelid = c.oid AND "
|
|
" c.relam = a.oid AND "
|
|
" c.relnamespace = n.oid AND "
|
|
" a.amname IN ('hash', 'gin') AND "
|
|
SKIP_TSVECTOR_TABLES);
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_relname = PQfnumber(res, "relname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
found = true;
|
|
if (!check_mode)
|
|
{
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "\\connect %s\n",
|
|
quote_identifier(active_db->db_name));
|
|
db_used = true;
|
|
}
|
|
fprintf(script, "REINDEX INDEX %s.%s;\n",
|
|
quote_identifier(PQgetvalue(res, rowno, i_nspname)),
|
|
quote_identifier(PQgetvalue(res, rowno, i_relname)));
|
|
}
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
if (!check_mode && found)
|
|
/* mark hash and gin indexes as invalid */
|
|
PQclear(executeQueryOrDie(conn,
|
|
"UPDATE pg_catalog.pg_index i "
|
|
"SET indisvalid = false "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_am a, "
|
|
" pg_catalog.pg_namespace n "
|
|
"WHERE i.indexrelid = c.oid AND "
|
|
" c.relam = a.oid AND "
|
|
" c.relnamespace = n.oid AND "
|
|
" a.amname IN ('hash', 'gin')"));
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
if (found)
|
|
{
|
|
report_status(PG_WARNING, "warning");
|
|
if (check_mode)
|
|
pg_log(PG_WARNING, "\n"
|
|
"Your installation contains hash and/or GIN indexes. These indexes have\n"
|
|
"different internal formats between your old and new clusters, so they\n"
|
|
"must be reindexed with the REINDEX command. After upgrading, you will\n"
|
|
"be given REINDEX instructions.\n\n");
|
|
else
|
|
pg_log(PG_WARNING, "\n"
|
|
"Your installation contains hash and/or GIN indexes. These indexes have\n"
|
|
"different internal formats between your old and new clusters, so they\n"
|
|
"must be reindexed with the REINDEX command. The file:\n"
|
|
" %s\n"
|
|
"when executed by psql by the database superuser will recreate all invalid\n"
|
|
"indexes; until then, none of these indexes will be used.\n\n",
|
|
output_path);
|
|
}
|
|
else
|
|
check_ok();
|
|
}
|
|
|
|
|
|
/*
|
|
* old_8_3_invalidate_bpchar_pattern_ops_indexes()
|
|
* 8.3 -> 8.4
|
|
* 8.4 bpchar_pattern_ops no longer sorts based on trailing spaces
|
|
*/
|
|
void
|
|
old_8_3_invalidate_bpchar_pattern_ops_indexes(ClusterInfo *cluster,
|
|
bool check_mode)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char output_path[MAXPGPATH];
|
|
|
|
prep_status("Checking for bpchar_pattern_ops indexes");
|
|
|
|
snprintf(output_path, sizeof(output_path), "reindex_bpchar_ops.sql");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_relname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/* find bpchar_pattern_ops indexes */
|
|
|
|
/*
|
|
* Do only non-hash, non-gin indexees; we already invalidated them
|
|
* above; no need to reindex twice
|
|
*/
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, c.relname "
|
|
"FROM pg_catalog.pg_index i, "
|
|
" pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_namespace n "
|
|
"WHERE indexrelid = c.oid AND "
|
|
" c.relnamespace = n.oid AND "
|
|
" ( "
|
|
" SELECT o.oid "
|
|
" FROM pg_catalog.pg_opclass o, "
|
|
" pg_catalog.pg_am a"
|
|
" WHERE a.amname NOT IN ('hash', 'gin') AND "
|
|
" a.oid = o.opcmethod AND "
|
|
" o.opcname = 'bpchar_pattern_ops') "
|
|
" = ANY (i.indclass) AND "
|
|
SKIP_TSVECTOR_TABLES);
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_relname = PQfnumber(res, "relname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
found = true;
|
|
if (!check_mode)
|
|
{
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "\\connect %s\n",
|
|
quote_identifier(active_db->db_name));
|
|
db_used = true;
|
|
}
|
|
fprintf(script, "REINDEX INDEX %s.%s;\n",
|
|
quote_identifier(PQgetvalue(res, rowno, i_nspname)),
|
|
quote_identifier(PQgetvalue(res, rowno, i_relname)));
|
|
}
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
if (!check_mode && found)
|
|
/* mark bpchar_pattern_ops indexes as invalid */
|
|
PQclear(executeQueryOrDie(conn,
|
|
"UPDATE pg_catalog.pg_index i "
|
|
"SET indisvalid = false "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_namespace n "
|
|
"WHERE indexrelid = c.oid AND "
|
|
" c.relnamespace = n.oid AND "
|
|
" ( "
|
|
" SELECT o.oid "
|
|
" FROM pg_catalog.pg_opclass o, "
|
|
" pg_catalog.pg_am a"
|
|
" WHERE a.amname NOT IN ('hash', 'gin') AND "
|
|
" a.oid = o.opcmethod AND "
|
|
" o.opcname = 'bpchar_pattern_ops') "
|
|
" = ANY (i.indclass)"));
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
if (found)
|
|
{
|
|
report_status(PG_WARNING, "warning");
|
|
if (check_mode)
|
|
pg_log(PG_WARNING, "\n"
|
|
"Your installation contains indexes using \"bpchar_pattern_ops\". These\n"
|
|
"indexes have different internal formats between your old and new clusters\n"
|
|
"so they must be reindexed with the REINDEX command. After upgrading, you\n"
|
|
"will be given REINDEX instructions.\n\n");
|
|
else
|
|
pg_log(PG_WARNING, "\n"
|
|
"Your installation contains indexes using \"bpchar_pattern_ops\". These\n"
|
|
"indexes have different internal formats between your old and new clusters\n"
|
|
"so they must be reindexed with the REINDEX command. The file:\n"
|
|
" %s\n"
|
|
"when executed by psql by the database superuser will recreate all invalid\n"
|
|
"indexes; until then, none of these indexes will be used.\n\n",
|
|
output_path);
|
|
}
|
|
else
|
|
check_ok();
|
|
}
|
|
|
|
|
|
/*
|
|
* old_8_3_create_sequence_script()
|
|
* 8.3 -> 8.4
|
|
* 8.4 added the column "start_value" to all sequences. For this reason,
|
|
* we don't transfer sequence files but instead use the CREATE SEQUENCE
|
|
* command from the schema dump, and use setval() to restore the sequence
|
|
* value and 'is_called' from the old database. This is safe to run
|
|
* by pg_upgrade because sequence files are not transferred from the old
|
|
* server, even in link mode.
|
|
*/
|
|
char *
|
|
old_8_3_create_sequence_script(ClusterInfo *cluster)
|
|
{
|
|
int dbnum;
|
|
FILE *script = NULL;
|
|
bool found = false;
|
|
char *output_path;
|
|
|
|
output_path = pg_strdup("adjust_sequences.sql");
|
|
|
|
prep_status("Creating script to adjust sequences");
|
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
|
{
|
|
PGresult *res;
|
|
bool db_used = false;
|
|
int ntups;
|
|
int rowno;
|
|
int i_nspname,
|
|
i_relname;
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
|
|
|
/* Find any sequences */
|
|
res = executeQueryOrDie(conn,
|
|
"SELECT n.nspname, c.relname "
|
|
"FROM pg_catalog.pg_class c, "
|
|
" pg_catalog.pg_namespace n "
|
|
"WHERE c.relkind = 'S' AND "
|
|
" c.relnamespace = n.oid AND "
|
|
/* exclude possible orphaned temp tables */
|
|
" n.nspname !~ '^pg_temp_' AND "
|
|
" n.nspname !~ '^pg_toast_temp_' AND "
|
|
" n.nspname NOT IN ('pg_catalog', 'information_schema')");
|
|
|
|
ntups = PQntuples(res);
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
i_relname = PQfnumber(res, "relname");
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
{
|
|
PGresult *seq_res;
|
|
int i_last_value,
|
|
i_is_called;
|
|
const char *nspname = PQgetvalue(res, rowno, i_nspname);
|
|
const char *relname = PQgetvalue(res, rowno, i_relname);
|
|
|
|
found = true;
|
|
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText(errno));
|
|
if (!db_used)
|
|
{
|
|
fprintf(script, "\\connect %s\n\n",
|
|
quote_identifier(active_db->db_name));
|
|
db_used = true;
|
|
}
|
|
|
|
/* Find the desired sequence */
|
|
seq_res = executeQueryOrDie(conn,
|
|
"SELECT s.last_value, s.is_called "
|
|
"FROM %s.%s s",
|
|
quote_identifier(nspname),
|
|
quote_identifier(relname));
|
|
|
|
assert(PQntuples(seq_res) == 1);
|
|
i_last_value = PQfnumber(seq_res, "last_value");
|
|
i_is_called = PQfnumber(seq_res, "is_called");
|
|
|
|
fprintf(script, "SELECT setval('%s.%s', %s, '%s');\n",
|
|
quote_identifier(nspname), quote_identifier(relname),
|
|
PQgetvalue(seq_res, 0, i_last_value), PQgetvalue(seq_res, 0, i_is_called));
|
|
PQclear(seq_res);
|
|
}
|
|
if (db_used)
|
|
fprintf(script, "\n");
|
|
|
|
PQclear(res);
|
|
|
|
PQfinish(conn);
|
|
}
|
|
|
|
if (script)
|
|
fclose(script);
|
|
|
|
check_ok();
|
|
|
|
if (found)
|
|
return output_path;
|
|
else
|
|
{
|
|
pg_free(output_path);
|
|
return NULL;
|
|
}
|
|
}
|