2010-05-12 10:19:11 +08:00
|
|
|
/*
|
|
|
|
* check.c
|
|
|
|
*
|
|
|
|
* server checks and output routines
|
2010-07-03 22:23:14 +08:00
|
|
|
*
|
2012-01-02 07:01:58 +08:00
|
|
|
* Copyright (c) 2010-2012, PostgreSQL Global Development Group
|
2010-09-21 04:08:53 +08:00
|
|
|
* contrib/pg_upgrade/check.c
|
2010-05-12 10:19:11 +08:00
|
|
|
*/
|
|
|
|
|
2011-08-27 09:16:24 +08:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
#include "pg_upgrade.h"
|
|
|
|
|
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
static void set_locale_and_encoding(ClusterInfo *cluster);
|
2011-04-20 09:00:29 +08:00
|
|
|
static void check_new_cluster_is_empty(void);
|
2010-10-20 05:38:16 +08:00
|
|
|
static void check_locale_and_encoding(ControlData *oldctrl,
|
2010-05-12 10:19:11 +08:00
|
|
|
ControlData *newctrl);
|
2011-05-07 20:55:13 +08:00
|
|
|
static void check_is_super_user(ClusterInfo *cluster);
|
2011-06-15 02:53:35 +08:00
|
|
|
static void check_for_prepared_transactions(ClusterInfo *cluster);
|
2011-01-02 01:06:36 +08:00
|
|
|
static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
|
|
|
|
static void check_for_reg_data_type_usage(ClusterInfo *cluster);
|
2011-06-23 08:48:34 +08:00
|
|
|
static void get_bin_version(ClusterInfo *cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
output_check_banner(bool *live_check)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
if (user_opts.check && is_server_running(old_cluster.pgdata))
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
*live_check = true;
|
2011-07-02 06:17:12 +08:00
|
|
|
if (old_cluster.port == DEF_PGUPORT)
|
|
|
|
pg_log(PG_FATAL, "When checking a live old server, "
|
|
|
|
"you must specify the old server's port number.\n");
|
2010-10-20 05:38:16 +08:00
|
|
|
if (old_cluster.port == new_cluster.port)
|
|
|
|
pg_log(PG_FATAL, "When checking a live server, "
|
2010-05-12 10:19:11 +08:00
|
|
|
"the old and new port numbers must be different.\n");
|
2011-06-23 02:48:59 +08:00
|
|
|
pg_log(PG_REPORT, "Performing Consistency Checks on Old Live Server\n");
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "------------------------------------------------\n");
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "Performing Consistency Checks\n");
|
|
|
|
pg_log(PG_REPORT, "-----------------------------\n");
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2011-06-23 07:30:12 +08:00
|
|
|
check_old_cluster(bool live_check, char **sequence_script_file_name)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
/* -- OLD -- */
|
|
|
|
|
|
|
|
if (!live_check)
|
2011-04-26 08:17:48 +08:00
|
|
|
start_postmaster(&old_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
set_locale_and_encoding(&old_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
get_pg_database_relfilenode(&old_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* Extract a list of databases and tables from the old cluster */
|
2011-01-02 01:06:36 +08:00
|
|
|
get_db_and_rel_infos(&old_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
init_tablespaces();
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
get_loadable_libraries();
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for various failure cases
|
|
|
|
*/
|
2011-05-07 20:55:13 +08:00
|
|
|
check_is_super_user(&old_cluster);
|
2011-06-15 02:53:35 +08:00
|
|
|
check_for_prepared_transactions(&old_cluster);
|
2011-01-02 01:06:36 +08:00
|
|
|
check_for_reg_data_type_usage(&old_cluster);
|
|
|
|
check_for_isn_and_int8_passing_mismatch(&old_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* old = PG 8.3 checks? */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 803)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-01-02 01:06:36 +08:00
|
|
|
old_8_3_check_for_name_data_type_usage(&old_cluster);
|
|
|
|
old_8_3_check_for_tsquery_usage(&old_cluster);
|
2011-09-08 02:42:34 +08:00
|
|
|
old_8_3_check_ltree_usage(&old_cluster);
|
2010-10-20 05:38:16 +08:00
|
|
|
if (user_opts.check)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-01-02 01:06:36 +08:00
|
|
|
old_8_3_rebuild_tsvector_tables(&old_cluster, true);
|
|
|
|
old_8_3_invalidate_hash_gin_indexes(&old_cluster, true);
|
|
|
|
old_8_3_invalidate_bpchar_pattern_ops_indexes(&old_cluster, true);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
/*
|
|
|
|
* While we have the old server running, create the script to
|
|
|
|
* properly restore its sequence values but we report this at the
|
|
|
|
* end.
|
|
|
|
*/
|
|
|
|
*sequence_script_file_name =
|
2011-01-02 01:06:36 +08:00
|
|
|
old_8_3_create_sequence_script(&old_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Pre-PG 9.0 had no large object permissions */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
|
2011-01-02 01:06:36 +08:00
|
|
|
new_9_0_populate_pg_largeobject_metadata(&old_cluster, true);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* While not a check option, we do this now because this is the only time
|
|
|
|
* the old server is running.
|
|
|
|
*/
|
2010-10-20 05:38:16 +08:00
|
|
|
if (!user_opts.check)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
generate_old_dump();
|
|
|
|
split_old_dump();
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!live_check)
|
2011-04-26 08:17:48 +08:00
|
|
|
stop_postmaster(false);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
check_new_cluster(void)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-01-02 01:06:36 +08:00
|
|
|
set_locale_and_encoding(&new_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2011-04-20 09:00:29 +08:00
|
|
|
get_db_and_rel_infos(&new_cluster);
|
|
|
|
|
|
|
|
check_new_cluster_is_empty();
|
2011-06-15 02:53:35 +08:00
|
|
|
check_for_prepared_transactions(&new_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
check_loadable_libraries();
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
check_locale_and_encoding(&old_cluster.controldata, &new_cluster.controldata);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
if (user_opts.transfer_mode == TRANSFER_MODE_LINK)
|
|
|
|
check_hard_link();
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
report_clusters_compatible(void)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
if (user_opts.check)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "\n*Clusters are compatible*\n");
|
2010-05-12 10:19:11 +08:00
|
|
|
/* stops new cluster */
|
2011-04-26 08:17:48 +08:00
|
|
|
stop_postmaster(false);
|
2011-04-07 04:00:44 +08:00
|
|
|
exit(0);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "\n"
|
2012-03-06 10:19:54 +08:00
|
|
|
"If pg_upgrade fails after this point, you must re-initdb the\n"
|
|
|
|
"new cluster before continuing.\n");
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
issue_warnings(char *sequence_script_file_name)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
/* old = PG 8.3 warnings? */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 803)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-04-26 08:17:48 +08:00
|
|
|
start_postmaster(&new_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* restore proper sequence values using file created from old server */
|
|
|
|
if (sequence_script_file_name)
|
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
prep_status("Adjusting sequences");
|
2012-03-13 07:47:54 +08:00
|
|
|
exec_prog(true, true, UTILITY_LOG_FILE,
|
|
|
|
SYSTEMQUOTE "\"%s/psql\" --echo-queries "
|
|
|
|
"--set ON_ERROR_STOP=on "
|
2010-10-20 06:37:04 +08:00
|
|
|
"--no-psqlrc --port %d --username \"%s\" "
|
2012-03-13 07:47:54 +08:00
|
|
|
"-f \"%s\" --dbname template1 >> \"%s\" 2>&1" SYSTEMQUOTE,
|
2010-10-20 05:38:16 +08:00
|
|
|
new_cluster.bindir, new_cluster.port, os_info.user,
|
2012-03-13 07:47:54 +08:00
|
|
|
sequence_script_file_name, UTILITY_LOG_FILE);
|
2010-05-12 10:19:11 +08:00
|
|
|
unlink(sequence_script_file_name);
|
2010-10-20 05:38:16 +08:00
|
|
|
check_ok();
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
old_8_3_rebuild_tsvector_tables(&new_cluster, false);
|
|
|
|
old_8_3_invalidate_hash_gin_indexes(&new_cluster, false);
|
|
|
|
old_8_3_invalidate_bpchar_pattern_ops_indexes(&new_cluster, false);
|
2011-04-26 08:17:48 +08:00
|
|
|
stop_postmaster(false);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create dummy large object permissions for old < PG 9.0? */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-04-26 08:17:48 +08:00
|
|
|
start_postmaster(&new_cluster);
|
2011-01-02 01:06:36 +08:00
|
|
|
new_9_0_populate_pg_largeobject_metadata(&new_cluster, false);
|
2011-04-26 08:17:48 +08:00
|
|
|
stop_postmaster(false);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2012-03-17 06:54:11 +08:00
|
|
|
output_completion_banner(char *analyze_script_file_name,
|
|
|
|
char *deletion_script_file_name)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2010-12-15 20:11:31 +08:00
|
|
|
/* Did we copy the free space files? */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) >= 804)
|
|
|
|
pg_log(PG_REPORT,
|
2012-03-17 06:54:11 +08:00
|
|
|
"Optimizer statistics are not transferred by pg_upgrade so,\n"
|
|
|
|
"once you start the new server, consider running:\n"
|
|
|
|
" %s\n\n", analyze_script_file_name);
|
2010-05-12 10:19:11 +08:00
|
|
|
else
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT,
|
2011-07-12 12:13:51 +08:00
|
|
|
"Optimizer statistics and free space information are not transferred\n"
|
2012-03-17 06:54:11 +08:00
|
|
|
"by pg_upgrade so, once you start the new server, consider running:\n"
|
|
|
|
" %s\n\n", analyze_script_file_name);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT,
|
2011-07-12 12:13:51 +08:00
|
|
|
"Running this script will delete the old cluster's data files:\n"
|
|
|
|
" %s\n",
|
2010-05-12 10:19:11 +08:00
|
|
|
deletion_script_file_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
check_cluster_versions(void)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-06-23 08:48:34 +08:00
|
|
|
prep_status("Checking cluster versions");
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
/* get old and new cluster versions */
|
2011-01-02 01:28:48 +08:00
|
|
|
old_cluster.major_version = get_major_server_version(&old_cluster);
|
|
|
|
new_cluster.major_version = get_major_server_version(&new_cluster);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2011-04-10 23:42:00 +08:00
|
|
|
/*
|
|
|
|
* We allow upgrades from/to the same major version for alpha/beta
|
|
|
|
* upgrades
|
|
|
|
*/
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) < 803)
|
|
|
|
pg_log(PG_FATAL, "This utility can only upgrade from PostgreSQL version 8.3 and later.\n");
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* Only current PG version is supported as a target */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM))
|
|
|
|
pg_log(PG_FATAL, "This utility can only upgrade to PostgreSQL version %s.\n",
|
2010-07-07 03:19:02 +08:00
|
|
|
PG_MAJORVERSION);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't allow downgrading because we use the target pg_dumpall, and
|
2011-06-23 08:48:34 +08:00
|
|
|
* pg_dumpall cannot operate on new database versions, only older versions.
|
2010-05-12 10:19:11 +08:00
|
|
|
*/
|
2010-10-20 05:38:16 +08:00
|
|
|
if (old_cluster.major_version > new_cluster.major_version)
|
|
|
|
pg_log(PG_FATAL, "This utility cannot be used to downgrade to older major PostgreSQL versions.\n");
|
2011-06-23 08:48:34 +08:00
|
|
|
|
|
|
|
/* get old and new binary versions */
|
|
|
|
get_bin_version(&old_cluster);
|
|
|
|
get_bin_version(&new_cluster);
|
|
|
|
|
|
|
|
/* Ensure binaries match the designated data directories */
|
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) !=
|
|
|
|
GET_MAJOR_VERSION(old_cluster.bin_version))
|
|
|
|
pg_log(PG_FATAL,
|
|
|
|
"Old cluster data and binary directories are from different major versions.\n");
|
|
|
|
if (GET_MAJOR_VERSION(new_cluster.major_version) !=
|
|
|
|
GET_MAJOR_VERSION(new_cluster.bin_version))
|
|
|
|
pg_log(PG_FATAL,
|
|
|
|
"New cluster data and binary directories are from different major versions.\n");
|
|
|
|
|
|
|
|
check_ok();
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-20 05:38:16 +08:00
|
|
|
check_cluster_compatibility(bool live_check)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
/* get/check pg_control data of servers */
|
2010-10-20 05:38:16 +08:00
|
|
|
get_control_data(&old_cluster, live_check);
|
|
|
|
get_control_data(&new_cluster, false);
|
|
|
|
check_control_data(&old_cluster.controldata, &new_cluster.controldata);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* Is it 9.0 but without tablespace directories? */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(new_cluster.major_version) == 900 &&
|
2011-04-26 00:00:21 +08:00
|
|
|
new_cluster.controldata.cat_ver < TABLE_SPACE_SUBDIRS_CAT_VER)
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_FATAL, "This utility can only upgrade to PostgreSQL version 9.0 after 2010-01-11\n"
|
2010-05-12 10:19:11 +08:00
|
|
|
"because of backend API changes made during development.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set_locale_and_encoding()
|
|
|
|
*
|
|
|
|
* query the database to get the template0 locale
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-02 01:06:36 +08:00
|
|
|
set_locale_and_encoding(ClusterInfo *cluster)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
2011-01-02 01:06:36 +08:00
|
|
|
ControlData *ctrl = &cluster->controldata;
|
2010-05-12 10:19:11 +08:00
|
|
|
PGconn *conn;
|
|
|
|
PGresult *res;
|
|
|
|
int i_encoding;
|
2011-01-02 01:06:36 +08:00
|
|
|
int cluster_version = cluster->major_version;
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
conn = connectToServer(cluster, "template1");
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* for pg < 80400, we got the values from pg_controldata */
|
|
|
|
if (cluster_version >= 80400)
|
|
|
|
{
|
|
|
|
int i_datcollate;
|
|
|
|
int i_datctype;
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
res = executeQueryOrDie(conn,
|
2010-05-12 10:19:11 +08:00
|
|
|
"SELECT datcollate, datctype "
|
|
|
|
"FROM pg_catalog.pg_database "
|
|
|
|
"WHERE datname = 'template0' ");
|
|
|
|
assert(PQntuples(res) == 1);
|
|
|
|
|
|
|
|
i_datcollate = PQfnumber(res, "datcollate");
|
|
|
|
i_datctype = PQfnumber(res, "datctype");
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
ctrl->lc_collate = pg_strdup(PQgetvalue(res, 0, i_datcollate));
|
|
|
|
ctrl->lc_ctype = pg_strdup(PQgetvalue(res, 0, i_datctype));
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
PQclear(res);
|
|
|
|
}
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
res = executeQueryOrDie(conn,
|
2010-05-12 10:19:11 +08:00
|
|
|
"SELECT pg_catalog.pg_encoding_to_char(encoding) "
|
|
|
|
"FROM pg_catalog.pg_database "
|
|
|
|
"WHERE datname = 'template0' ");
|
|
|
|
assert(PQntuples(res) == 1);
|
|
|
|
|
|
|
|
i_encoding = PQfnumber(res, "pg_encoding_to_char");
|
2010-10-20 05:38:16 +08:00
|
|
|
ctrl->encoding = pg_strdup(PQgetvalue(res, 0, i_encoding));
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
PQclear(res);
|
|
|
|
|
|
|
|
PQfinish(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check_locale_and_encoding()
|
|
|
|
*
|
|
|
|
* locale is not in pg_controldata in 8.4 and later so
|
|
|
|
* we probably had to get via a database query.
|
|
|
|
*/
|
|
|
|
static void
|
2010-10-20 05:38:16 +08:00
|
|
|
check_locale_and_encoding(ControlData *oldctrl,
|
2010-05-12 10:19:11 +08:00
|
|
|
ControlData *newctrl)
|
|
|
|
{
|
2011-05-25 03:59:00 +08:00
|
|
|
/* These are often defined with inconsistent case, so use pg_strcasecmp(). */
|
|
|
|
if (pg_strcasecmp(oldctrl->lc_collate, newctrl->lc_collate) != 0)
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_FATAL,
|
2010-05-12 10:19:11 +08:00
|
|
|
"old and new cluster lc_collate values do not match\n");
|
2011-05-25 03:59:00 +08:00
|
|
|
if (pg_strcasecmp(oldctrl->lc_ctype, newctrl->lc_ctype) != 0)
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_FATAL,
|
2010-05-12 10:19:11 +08:00
|
|
|
"old and new cluster lc_ctype values do not match\n");
|
2011-05-25 03:59:00 +08:00
|
|
|
if (pg_strcasecmp(oldctrl->encoding, newctrl->encoding) != 0)
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_FATAL,
|
2010-05-12 10:19:11 +08:00
|
|
|
"old and new cluster encoding values do not match\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2011-04-20 09:00:29 +08:00
|
|
|
check_new_cluster_is_empty(void)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
int dbnum;
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
int relnum;
|
2010-10-20 05:38:16 +08:00
|
|
|
RelInfoArr *rel_arr = &new_cluster.dbarr.dbs[dbnum].rel_arr;
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
for (relnum = 0; relnum < rel_arr->nrels;
|
|
|
|
relnum++)
|
|
|
|
{
|
|
|
|
/* pg_largeobject and its index should be skipped */
|
|
|
|
if (strcmp(rel_arr->rels[relnum].nspname, "pg_catalog") != 0)
|
2011-04-20 09:00:29 +08:00
|
|
|
pg_log(PG_FATAL, "New cluster database \"%s\" is not empty\n",
|
2011-06-10 02:32:50 +08:00
|
|
|
new_cluster.dbarr.dbs[dbnum].db_name);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 09:00:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-17 06:54:11 +08:00
|
|
|
/*
|
|
|
|
* create_script_for_cluster_analyze()
|
|
|
|
*
|
|
|
|
* This incrementally generates better optimizer statistics
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
create_script_for_cluster_analyze(char **analyze_script_file_name)
|
|
|
|
{
|
|
|
|
FILE *script = NULL;
|
|
|
|
|
|
|
|
*analyze_script_file_name = pg_malloc(MAXPGPATH);
|
|
|
|
|
|
|
|
prep_status("Creating script to analyze new cluster");
|
|
|
|
|
|
|
|
snprintf(*analyze_script_file_name, MAXPGPATH, "analyze_new_cluster.%s",
|
|
|
|
SCRIPT_EXT);
|
|
|
|
|
|
|
|
if ((script = fopen_priv(*analyze_script_file_name, "w")) == NULL)
|
|
|
|
pg_log(PG_FATAL, "Could not open file \"%s\": %s\n",
|
|
|
|
*analyze_script_file_name, getErrorText(errno));
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
/* add shebang header */
|
|
|
|
fprintf(script, "#!/bin/sh\n\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fprintf(script, "echo %sThis script will generate minimal optimizer statistics rapidly%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %sso your system is usable, and then gather statistics twice more%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %swith increasing accuracy. When it is done, your system will%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %shave the default level of optimizer statistics.%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo\n\n");
|
|
|
|
|
|
|
|
fprintf(script, "echo %sIf you have used ALTER TABLE to modify the statistics target for%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %sany tables, you might want to remove them and restore them after%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %srunning this script because they will delay fast statistics generation.%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo\n\n");
|
|
|
|
|
|
|
|
fprintf(script, "echo %sIf you would like default statistics as quickly as possible, cancel%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %sthis script and run:%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %s vacuumdb --all %s%s\n", ECHO_QUOTE,
|
|
|
|
/* Did we copy the free space files? */
|
|
|
|
(GET_MAJOR_VERSION(old_cluster.major_version) >= 804) ?
|
|
|
|
"--analyze-only" : "--analyze", ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo\n\n");
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
fprintf(script, "sleep 2\n");
|
|
|
|
fprintf(script, "PGOPTIONS='-c default_statistics_target=1 -c vacuum_cost_delay=0'\n");
|
|
|
|
/* only need to export once */
|
|
|
|
fprintf(script, "export PGOPTIONS\n");
|
|
|
|
#else
|
|
|
|
fprintf(script, "REM simulate sleep 2\n");
|
|
|
|
fprintf(script, "PING 1.1.1.1 -n 1 -w 2000 > nul\n");
|
|
|
|
fprintf(script, "SET PGOPTIONS=-c default_statistics_target=1 -c vacuum_cost_delay=0\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fprintf(script, "echo %sGenerating minimal optimizer statistics (1 target)%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %s--------------------------------------------------%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "vacuumdb --all --analyze-only\n");
|
|
|
|
fprintf(script, "echo\n");
|
|
|
|
fprintf(script, "echo %sThe server is now available with minimal optimizer statistics.%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %sQuery performance will be optimal once this script completes.%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo\n\n");
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
fprintf(script, "sleep 2\n");
|
|
|
|
fprintf(script, "PGOPTIONS='-c default_statistics_target=10'\n");
|
|
|
|
#else
|
|
|
|
fprintf(script, "REM simulate sleep\n");
|
|
|
|
fprintf(script, "PING 1.1.1.1 -n 1 -w 2000 > nul\n");
|
|
|
|
fprintf(script, "SET PGOPTIONS=-c default_statistics_target=10\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fprintf(script, "echo %sGenerating medium optimizer statistics (10 targets)%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %s---------------------------------------------------%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "vacuumdb --all --analyze-only\n");
|
|
|
|
fprintf(script, "echo\n\n");
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
fprintf(script, "unset PGOPTIONS\n");
|
|
|
|
#else
|
|
|
|
fprintf(script, "SET PGOPTIONS\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fprintf(script, "echo %sGenerating default (full) optimizer statistics (100 targets?)%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "echo %s-------------------------------------------------------------%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
fprintf(script, "vacuumdb --all %s\n",
|
|
|
|
/* Did we copy the free space files? */
|
|
|
|
(GET_MAJOR_VERSION(old_cluster.major_version) >= 804) ?
|
|
|
|
"--analyze-only" : "--analyze");
|
|
|
|
|
|
|
|
fprintf(script, "echo\n\n");
|
|
|
|
fprintf(script, "echo %sDone%s\n",
|
|
|
|
ECHO_QUOTE, ECHO_QUOTE);
|
|
|
|
|
|
|
|
fclose(script);
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
if (chmod(*analyze_script_file_name, S_IRWXU) != 0)
|
|
|
|
pg_log(PG_FATAL, "Could not add execute permission to file \"%s\": %s\n",
|
|
|
|
*analyze_script_file_name, getErrorText(errno));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
check_ok();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
/*
|
|
|
|
* create_script_for_old_cluster_deletion()
|
|
|
|
*
|
|
|
|
* This is particularly useful for tablespace deletion.
|
|
|
|
*/
|
|
|
|
void
|
2011-06-23 05:50:40 +08:00
|
|
|
create_script_for_old_cluster_deletion(char **deletion_script_file_name)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
FILE *script = NULL;
|
|
|
|
int tblnum;
|
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
*deletion_script_file_name = pg_malloc(MAXPGPATH);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
prep_status("Creating script to delete old cluster");
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2012-03-13 07:47:54 +08:00
|
|
|
snprintf(*deletion_script_file_name, MAXPGPATH, "delete_old_cluster.%s",
|
|
|
|
SCRIPT_EXT);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2012-03-13 07:47:54 +08:00
|
|
|
if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL)
|
2011-07-12 12:13:51 +08:00
|
|
|
pg_log(PG_FATAL, "Could not open file \"%s\": %s\n",
|
|
|
|
*deletion_script_file_name, getErrorText(errno));
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
/* add shebang header */
|
|
|
|
fprintf(script, "#!/bin/sh\n\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* delete old cluster's default tablespace */
|
2010-10-20 05:38:16 +08:00
|
|
|
fprintf(script, RMDIR_CMD " %s\n", old_cluster.pgdata);
|
2010-05-12 10:19:11 +08:00
|
|
|
|
|
|
|
/* delete old cluster's alternate tablespaces */
|
2010-10-20 05:38:16 +08:00
|
|
|
for (tblnum = 0; tblnum < os_info.num_tablespaces; tblnum++)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Do the old cluster's per-database directories share a directory
|
|
|
|
* with a new version-specific tablespace?
|
|
|
|
*/
|
2010-10-20 05:38:16 +08:00
|
|
|
if (strlen(old_cluster.tablespace_suffix) == 0)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
/* delete per-database directories */
|
|
|
|
int dbnum;
|
|
|
|
|
|
|
|
fprintf(script, "\n");
|
2010-10-19 23:52:43 +08:00
|
|
|
/* remove PG_VERSION? */
|
2010-10-20 05:38:16 +08:00
|
|
|
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
|
2010-10-19 23:52:43 +08:00
|
|
|
fprintf(script, RM_CMD " %s%s/PG_VERSION\n",
|
2010-10-20 06:37:04 +08:00
|
|
|
os_info.tablespaces[tblnum], old_cluster.tablespace_suffix);
|
2010-10-19 23:52:43 +08:00
|
|
|
|
2011-11-02 01:49:03 +08:00
|
|
|
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
2010-05-12 10:19:11 +08:00
|
|
|
{
|
|
|
|
fprintf(script, RMDIR_CMD " %s%s/%d\n",
|
2010-10-20 06:37:04 +08:00
|
|
|
os_info.tablespaces[tblnum], old_cluster.tablespace_suffix,
|
2010-10-20 05:38:16 +08:00
|
|
|
old_cluster.dbarr.dbs[dbnum].db_oid);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2010-07-07 03:19:02 +08:00
|
|
|
|
2010-05-12 10:19:11 +08:00
|
|
|
/*
|
|
|
|
* Simply delete the tablespace directory, which might be ".old"
|
|
|
|
* or a version-specific subdirectory.
|
|
|
|
*/
|
|
|
|
fprintf(script, RMDIR_CMD " %s%s\n",
|
2010-10-20 06:37:04 +08:00
|
|
|
os_info.tablespaces[tblnum], old_cluster.tablespace_suffix);
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(script);
|
|
|
|
|
2010-05-13 23:58:15 +08:00
|
|
|
#ifndef WIN32
|
2010-05-12 10:19:11 +08:00
|
|
|
if (chmod(*deletion_script_file_name, S_IRWXU) != 0)
|
2011-07-12 12:13:51 +08:00
|
|
|
pg_log(PG_FATAL, "Could not add execute permission to file \"%s\": %s\n",
|
|
|
|
*deletion_script_file_name, getErrorText(errno));
|
2010-05-13 23:58:15 +08:00
|
|
|
#endif
|
2010-05-12 10:19:11 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
check_ok();
|
2010-05-12 10:19:11 +08:00
|
|
|
}
|
2010-07-25 11:28:32 +08:00
|
|
|
|
|
|
|
|
2011-05-07 20:55:13 +08:00
|
|
|
/*
|
|
|
|
* check_is_super_user()
|
|
|
|
*
|
|
|
|
* Make sure we are the super-user.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_is_super_user(ClusterInfo *cluster)
|
|
|
|
{
|
|
|
|
PGresult *res;
|
|
|
|
PGconn *conn = connectToServer(cluster, "template1");
|
|
|
|
|
2011-05-09 20:55:36 +08:00
|
|
|
prep_status("Checking database user is a superuser");
|
|
|
|
|
2011-05-07 20:55:13 +08:00
|
|
|
/* Can't use pg_authid because only superusers can view it. */
|
|
|
|
res = executeQueryOrDie(conn,
|
|
|
|
"SELECT rolsuper "
|
|
|
|
"FROM pg_catalog.pg_roles "
|
|
|
|
"WHERE rolname = current_user");
|
|
|
|
|
|
|
|
if (PQntuples(res) != 1 || strcmp(PQgetvalue(res, 0, 0), "t") != 0)
|
2011-05-08 00:17:21 +08:00
|
|
|
pg_log(PG_FATAL, "database user \"%s\" is not a superuser\n",
|
2011-06-10 02:32:50 +08:00
|
|
|
os_info.user);
|
2011-05-07 20:55:13 +08:00
|
|
|
|
|
|
|
PQclear(res);
|
|
|
|
|
|
|
|
PQfinish(conn);
|
2011-05-09 20:55:36 +08:00
|
|
|
|
|
|
|
check_ok();
|
2011-05-07 20:55:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-15 02:53:35 +08:00
|
|
|
/*
|
|
|
|
* check_for_prepared_transactions()
|
|
|
|
*
|
|
|
|
* Make sure there are no prepared transactions because the storage format
|
|
|
|
* might have changed.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_for_prepared_transactions(ClusterInfo *cluster)
|
|
|
|
{
|
|
|
|
PGresult *res;
|
|
|
|
PGconn *conn = connectToServer(cluster, "template1");
|
|
|
|
|
|
|
|
prep_status("Checking for prepared transactions");
|
|
|
|
|
|
|
|
res = executeQueryOrDie(conn,
|
|
|
|
"SELECT * "
|
2011-08-31 05:15:00 +08:00
|
|
|
"FROM pg_catalog.pg_prepared_xacts");
|
2011-06-15 02:53:35 +08:00
|
|
|
|
|
|
|
if (PQntuples(res) != 0)
|
|
|
|
pg_log(PG_FATAL, "The %s cluster contains prepared transactions\n",
|
|
|
|
CLUSTER_NAME(cluster));
|
|
|
|
|
|
|
|
PQclear(res);
|
|
|
|
|
|
|
|
PQfinish(conn);
|
|
|
|
|
|
|
|
check_ok();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-25 11:47:29 +08:00
|
|
|
/*
|
2010-10-20 06:37:04 +08:00
|
|
|
* check_for_isn_and_int8_passing_mismatch()
|
2010-07-25 11:47:29 +08:00
|
|
|
*
|
2011-05-19 05:30:31 +08:00
|
|
|
* contrib/isn relies on data type int8, and in 8.4 int8 can now be passed
|
2010-07-25 11:47:29 +08:00
|
|
|
* by value. The schema dumps the CREATE TYPE PASSEDBYVALUE setting so
|
|
|
|
* it must match for the old and new servers.
|
|
|
|
*/
|
2011-03-07 09:14:01 +08:00
|
|
|
static void
|
2011-01-02 01:06:36 +08:00
|
|
|
check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
|
2010-07-25 11:47:29 +08:00
|
|
|
{
|
|
|
|
int dbnum;
|
|
|
|
FILE *script = NULL;
|
|
|
|
bool found = false;
|
|
|
|
char output_path[MAXPGPATH];
|
|
|
|
|
2011-05-19 05:30:31 +08:00
|
|
|
prep_status("Checking for contrib/isn with bigint-passing mismatch");
|
2010-07-25 11:47:29 +08:00
|
|
|
|
2010-10-20 05:38:16 +08:00
|
|
|
if (old_cluster.controldata.float8_pass_by_value ==
|
|
|
|
new_cluster.controldata.float8_pass_by_value)
|
2010-07-25 11:47:29 +08:00
|
|
|
{
|
|
|
|
/* no mismatch */
|
2010-10-20 05:38:16 +08:00
|
|
|
check_ok();
|
2010-07-25 11:47:29 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-13 07:47:54 +08:00
|
|
|
snprintf(output_path, sizeof(output_path),
|
|
|
|
"contrib_isn_and_int8_pass_by_value.txt");
|
2010-07-25 11:47:29 +08:00
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
2010-07-25 11:47:29 +08:00
|
|
|
{
|
|
|
|
PGresult *res;
|
|
|
|
bool db_used = false;
|
|
|
|
int ntups;
|
|
|
|
int rowno;
|
|
|
|
int i_nspname,
|
|
|
|
i_proname;
|
2011-01-02 01:06:36 +08:00
|
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
2010-07-25 11:47:29 +08:00
|
|
|
|
|
|
|
/* Find any functions coming from contrib/isn */
|
2010-10-20 05:38:16 +08:00
|
|
|
res = executeQueryOrDie(conn,
|
2010-07-25 11:47:29 +08:00
|
|
|
"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/isn'");
|
|
|
|
|
|
|
|
ntups = PQntuples(res);
|
|
|
|
i_nspname = PQfnumber(res, "nspname");
|
|
|
|
i_proname = PQfnumber(res, "proname");
|
|
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
|
|
{
|
|
|
|
found = true;
|
2012-03-13 07:47:54 +08:00
|
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
2011-07-12 12:13:51 +08:00
|
|
|
pg_log(PG_FATAL, "Could not open file \"%s\": %s\n",
|
|
|
|
output_path, getErrorText(errno));
|
2010-07-25 11:47:29 +08:00
|
|
|
if (!db_used)
|
|
|
|
{
|
2011-07-12 12:13:51 +08:00
|
|
|
fprintf(script, "Database: %s\n", active_db->db_name);
|
2010-07-25 11:47:29 +08:00
|
|
|
db_used = true;
|
|
|
|
}
|
|
|
|
fprintf(script, " %s.%s\n",
|
|
|
|
PQgetvalue(res, rowno, i_nspname),
|
|
|
|
PQgetvalue(res, rowno, i_proname));
|
|
|
|
}
|
|
|
|
|
|
|
|
PQclear(res);
|
|
|
|
|
|
|
|
PQfinish(conn);
|
|
|
|
}
|
|
|
|
|
2011-03-09 10:35:42 +08:00
|
|
|
if (script)
|
2011-04-10 23:42:00 +08:00
|
|
|
fclose(script);
|
2011-03-09 10:35:42 +08:00
|
|
|
|
2010-07-25 11:47:29 +08:00
|
|
|
if (found)
|
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "fatal\n");
|
|
|
|
pg_log(PG_FATAL,
|
2011-07-12 12:13:51 +08:00
|
|
|
"Your installation contains \"contrib/isn\" functions which rely on the\n"
|
|
|
|
"bigint data type. Your old and new clusters pass bigint values\n"
|
|
|
|
"differently so this cluster cannot currently be upgraded. You can\n"
|
|
|
|
"manually upgrade databases that use \"contrib/isn\" facilities and remove\n"
|
|
|
|
"\"contrib/isn\" from the old cluster and restart the upgrade. A list of\n"
|
|
|
|
"the problem functions is in the file:\n"
|
|
|
|
" %s\n\n", output_path);
|
2010-07-25 11:47:29 +08:00
|
|
|
}
|
|
|
|
else
|
2010-10-20 05:38:16 +08:00
|
|
|
check_ok();
|
2010-07-25 11:47:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-25 11:28:32 +08:00
|
|
|
/*
|
|
|
|
* check_for_reg_data_type_usage()
|
|
|
|
* pg_upgrade only preserves these system values:
|
2011-12-06 05:45:19 +08:00
|
|
|
* pg_class.oid
|
2010-07-25 11:28:32 +08:00
|
|
|
* pg_type.oid
|
|
|
|
* pg_enum.oid
|
|
|
|
*
|
2011-12-06 05:45:19 +08:00
|
|
|
* Many of the reg* data types reference system catalog info that is
|
2010-07-25 11:28:32 +08:00
|
|
|
* not preserved, and hence these data types cannot be used in user
|
|
|
|
* tables upgraded by pg_upgrade.
|
|
|
|
*/
|
2011-03-07 09:14:01 +08:00
|
|
|
static void
|
2011-01-02 01:06:36 +08:00
|
|
|
check_for_reg_data_type_usage(ClusterInfo *cluster)
|
2010-07-25 11:28:32 +08:00
|
|
|
{
|
|
|
|
int dbnum;
|
|
|
|
FILE *script = NULL;
|
|
|
|
bool found = false;
|
|
|
|
char output_path[MAXPGPATH];
|
|
|
|
|
2011-07-12 12:13:51 +08:00
|
|
|
prep_status("Checking for reg* system OID user data types");
|
2010-07-25 11:28:32 +08:00
|
|
|
|
2012-03-13 07:47:54 +08:00
|
|
|
snprintf(output_path, sizeof(output_path), "tables_using_reg.txt");
|
2010-07-25 11:28:32 +08:00
|
|
|
|
2011-01-02 01:06:36 +08:00
|
|
|
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
2010-07-25 11:28:32 +08:00
|
|
|
{
|
|
|
|
PGresult *res;
|
|
|
|
bool db_used = false;
|
|
|
|
int ntups;
|
|
|
|
int rowno;
|
|
|
|
int i_nspname,
|
|
|
|
i_relname,
|
|
|
|
i_attname;
|
2011-01-02 01:06:36 +08:00
|
|
|
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
|
|
|
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
2010-07-25 11:28:32 +08:00
|
|
|
|
2012-01-20 05:04:34 +08:00
|
|
|
/*
|
|
|
|
* While several relkinds don't store any data, e.g. views, they
|
|
|
|
* can be used to define data types of other columns, so we
|
|
|
|
* check all relkinds.
|
|
|
|
*/
|
2010-10-20 05:38:16 +08:00
|
|
|
res = executeQueryOrDie(conn,
|
2010-07-25 11:28:32 +08:00
|
|
|
"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 "
|
|
|
|
" NOT a.attisdropped AND "
|
|
|
|
" a.atttypid IN ( "
|
2010-10-20 06:37:04 +08:00
|
|
|
" 'pg_catalog.regproc'::pg_catalog.regtype, "
|
2011-12-06 05:45:19 +08:00
|
|
|
" 'pg_catalog.regprocedure'::pg_catalog.regtype, "
|
2010-10-20 06:37:04 +08:00
|
|
|
" 'pg_catalog.regoper'::pg_catalog.regtype, "
|
2011-12-06 05:45:19 +08:00
|
|
|
" 'pg_catalog.regoperator'::pg_catalog.regtype, "
|
|
|
|
/* regclass.oid is preserved, so 'regclass' is OK */
|
2010-10-20 06:37:04 +08:00
|
|
|
/* regtype.oid is preserved, so 'regtype' is OK */
|
2011-12-06 05:45:19 +08:00
|
|
|
" 'pg_catalog.regconfig'::pg_catalog.regtype, "
|
|
|
|
" 'pg_catalog.regdictionary'::pg_catalog.regtype) AND "
|
|
|
|
" c.relnamespace = n.oid AND "
|
|
|
|
" n.nspname != 'pg_catalog' AND "
|
|
|
|
" n.nspname != 'information_schema'");
|
2010-07-25 11:28:32 +08:00
|
|
|
|
|
|
|
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;
|
2012-03-13 07:47:54 +08:00
|
|
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
2011-07-12 12:13:51 +08:00
|
|
|
pg_log(PG_FATAL, "Could not open file \"%s\": %s\n",
|
|
|
|
output_path, getErrorText(errno));
|
2010-07-25 11:28:32 +08:00
|
|
|
if (!db_used)
|
|
|
|
{
|
2011-07-12 12:13:51 +08:00
|
|
|
fprintf(script, "Database: %s\n", active_db->db_name);
|
2010-07-25 11:28:32 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-03-09 10:35:42 +08:00
|
|
|
if (script)
|
|
|
|
fclose(script);
|
|
|
|
|
2010-07-25 11:28:32 +08:00
|
|
|
if (found)
|
|
|
|
{
|
2010-10-20 05:38:16 +08:00
|
|
|
pg_log(PG_REPORT, "fatal\n");
|
|
|
|
pg_log(PG_FATAL,
|
2011-07-12 12:13:51 +08:00
|
|
|
"Your installation contains one of the reg* data types in user tables.\n"
|
|
|
|
"These data types reference system OIDs that are not preserved by\n"
|
|
|
|
"pg_upgrade, so this cluster cannot currently be upgraded. You can\n"
|
|
|
|
"remove the problem tables and restart the upgrade. A list of the problem\n"
|
|
|
|
"columns is in the file:\n"
|
|
|
|
" %s\n\n", output_path);
|
2010-07-25 11:28:32 +08:00
|
|
|
}
|
|
|
|
else
|
2010-10-20 05:38:16 +08:00
|
|
|
check_ok();
|
2010-07-25 11:28:32 +08:00
|
|
|
}
|
2011-06-23 05:47:23 +08:00
|
|
|
|
|
|
|
|
2011-06-23 08:48:34 +08:00
|
|
|
static void
|
|
|
|
get_bin_version(ClusterInfo *cluster)
|
|
|
|
{
|
|
|
|
char cmd[MAXPGPATH], cmd_output[MAX_STRING];
|
|
|
|
FILE *output;
|
|
|
|
int pre_dot, post_dot;
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "\"%s/pg_ctl\" --version", cluster->bindir);
|
|
|
|
|
2011-10-07 07:37:29 +08:00
|
|
|
if ((output = popen(cmd, "r")) == NULL ||
|
|
|
|
fgets(cmd_output, sizeof(cmd_output), output) == NULL)
|
|
|
|
pg_log(PG_FATAL, "Could not get pg_ctl version data using %s: %s\n",
|
|
|
|
cmd, getErrorText(errno));
|
2011-06-23 08:48:34 +08:00
|
|
|
|
|
|
|
pclose(output);
|
|
|
|
|
|
|
|
/* Remove trailing newline */
|
|
|
|
if (strchr(cmd_output, '\n') != NULL)
|
|
|
|
*strchr(cmd_output, '\n') = '\0';
|
|
|
|
|
|
|
|
if (sscanf(cmd_output, "%*s %*s %d.%d", &pre_dot, &post_dot) != 2)
|
|
|
|
pg_log(PG_FATAL, "could not get version from %s\n", cmd);
|
|
|
|
|
|
|
|
cluster->bin_version = (pre_dot * 100 + post_dot) * 100;
|
|
|
|
}
|
|
|
|
|