mirror of https://github.com/postgres/postgres
This trims down the code, and is in preparation for hardening pg_upgrade against auto-oid assignment.pull/14/head
parent
b0488e5c4f
commit
2209b3923a
@ -1,769 +0,0 @@ |
||||
/*
|
||||
* version.c |
||||
* |
||||
* Postgres-version-specific routines |
||||
* |
||||
* Copyright (c) 2010-2014, 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; |
||||
} |
||||
} |
Loading…
Reference in new issue