mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
pg_upgrade: Preserve default char signedness value from old cluster.
Commit 44fe30fdab
introduced the 'default_char_signedness' field in
controlfile. Newly created database clusters always set this field to
'signed'.
This change ensures that pg_upgrade updates the
'default_char_signedness' to 'unsigned' if the source database cluster
has signedness=false. For source clusters from v17 or earlier, which
lack the 'default_char_signedness' information, pg_upgrade assumes the
source cluster was initialized on the same platform where pg_upgrade
is running. It then sets the 'default_char_signedness' value according
to the current platform's default character signedness.
Reviewed-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/CB11ADBC-0C3F-4FE0-A678-666EE80CBB07%40amazon.com
This commit is contained in:
@ -10,6 +10,7 @@
|
|||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <limits.h> /* for CHAR_MIN */
|
||||||
|
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
#include "pg_upgrade.h"
|
#include "pg_upgrade.h"
|
||||||
@ -62,6 +63,7 @@ get_control_data(ClusterInfo *cluster)
|
|||||||
bool got_date_is_int = false;
|
bool got_date_is_int = false;
|
||||||
bool got_data_checksum_version = false;
|
bool got_data_checksum_version = false;
|
||||||
bool got_cluster_state = false;
|
bool got_cluster_state = false;
|
||||||
|
bool got_default_char_signedness = false;
|
||||||
char *lc_collate = NULL;
|
char *lc_collate = NULL;
|
||||||
char *lc_ctype = NULL;
|
char *lc_ctype = NULL;
|
||||||
char *lc_monetary = NULL;
|
char *lc_monetary = NULL;
|
||||||
@ -501,6 +503,25 @@ get_control_data(ClusterInfo *cluster)
|
|||||||
cluster->controldata.data_checksum_version = str2uint(p);
|
cluster->controldata.data_checksum_version = str2uint(p);
|
||||||
got_data_checksum_version = true;
|
got_data_checksum_version = true;
|
||||||
}
|
}
|
||||||
|
else if ((p = strstr(bufin, "Default char data signedness:")) != NULL)
|
||||||
|
{
|
||||||
|
p = strchr(p, ':');
|
||||||
|
|
||||||
|
if (p == NULL || strlen(p) <= 1)
|
||||||
|
pg_fatal("%d: controldata retrieval problem", __LINE__);
|
||||||
|
|
||||||
|
/* Skip the colon and any whitespace after it */
|
||||||
|
p++;
|
||||||
|
while (isspace((unsigned char) *p))
|
||||||
|
p++;
|
||||||
|
|
||||||
|
/* The value should be either 'signed' or 'unsigned' */
|
||||||
|
if (strcmp(p, "signed") != 0 && strcmp(p, "unsigned") != 0)
|
||||||
|
pg_fatal("%d: controldata retrieval problem", __LINE__);
|
||||||
|
|
||||||
|
cluster->controldata.default_char_signedness = strcmp(p, "signed") == 0;
|
||||||
|
got_default_char_signedness = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = pclose(output);
|
rc = pclose(output);
|
||||||
@ -561,6 +582,21 @@ get_control_data(ClusterInfo *cluster)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pre-v18 database clusters don't have the default char signedness
|
||||||
|
* information. We use the char signedness of the platform where
|
||||||
|
* pg_upgrade was built.
|
||||||
|
*/
|
||||||
|
if (cluster->controldata.cat_ver < DEFAULT_CHAR_SIGNEDNESS_CAT_VER)
|
||||||
|
{
|
||||||
|
Assert(!got_default_char_signedness);
|
||||||
|
#if CHAR_MIN != 0
|
||||||
|
cluster->controldata.default_char_signedness = true;
|
||||||
|
#else
|
||||||
|
cluster->controldata.default_char_signedness = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* verify that we got all the mandatory pg_control data */
|
/* verify that we got all the mandatory pg_control data */
|
||||||
if (!got_xid || !got_oid ||
|
if (!got_xid || !got_oid ||
|
||||||
!got_multi || !got_oldestxid ||
|
!got_multi || !got_oldestxid ||
|
||||||
@ -572,7 +608,9 @@ get_control_data(ClusterInfo *cluster)
|
|||||||
!got_index || !got_toast ||
|
!got_index || !got_toast ||
|
||||||
(!got_large_object &&
|
(!got_large_object &&
|
||||||
cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) ||
|
cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) ||
|
||||||
!got_date_is_int || !got_data_checksum_version)
|
!got_date_is_int || !got_data_checksum_version ||
|
||||||
|
(!got_default_char_signedness &&
|
||||||
|
cluster->controldata.cat_ver >= DEFAULT_CHAR_SIGNEDNESS_CAT_VER))
|
||||||
{
|
{
|
||||||
if (cluster == &old_cluster)
|
if (cluster == &old_cluster)
|
||||||
pg_log(PG_REPORT,
|
pg_log(PG_REPORT,
|
||||||
@ -641,6 +679,10 @@ get_control_data(ClusterInfo *cluster)
|
|||||||
if (!got_data_checksum_version)
|
if (!got_data_checksum_version)
|
||||||
pg_log(PG_REPORT, " data checksum version");
|
pg_log(PG_REPORT, " data checksum version");
|
||||||
|
|
||||||
|
/* value added in Postgres 18 */
|
||||||
|
if (!got_default_char_signedness)
|
||||||
|
pg_log(PG_REPORT, " default char signedness");
|
||||||
|
|
||||||
pg_fatal("Cannot continue without required control information, terminating");
|
pg_fatal("Cannot continue without required control information, terminating");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
*/
|
*/
|
||||||
#define RESTORE_TRANSACTION_SIZE 1000
|
#define RESTORE_TRANSACTION_SIZE 1000
|
||||||
|
|
||||||
|
static void set_new_cluster_char_signedness(void);
|
||||||
static void set_locale_and_encoding(void);
|
static void set_locale_and_encoding(void);
|
||||||
static void prepare_new_cluster(void);
|
static void prepare_new_cluster(void);
|
||||||
static void prepare_new_globals(void);
|
static void prepare_new_globals(void);
|
||||||
@ -154,6 +155,7 @@ main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
copy_xact_xlog_xid();
|
copy_xact_xlog_xid();
|
||||||
|
set_new_cluster_char_signedness();
|
||||||
|
|
||||||
/* New now using xids of the old system */
|
/* New now using xids of the old system */
|
||||||
|
|
||||||
@ -388,6 +390,32 @@ setup(char *argv0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the new cluster's default char signedness using the old cluster's
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_new_cluster_char_signedness(void)
|
||||||
|
{
|
||||||
|
bool new_char_signedness;
|
||||||
|
|
||||||
|
/* Inherit the source database's signedness */
|
||||||
|
new_char_signedness = old_cluster.controldata.default_char_signedness;
|
||||||
|
|
||||||
|
/* Change the char signedness of the new cluster, if necessary */
|
||||||
|
if (new_cluster.controldata.default_char_signedness != new_char_signedness)
|
||||||
|
{
|
||||||
|
prep_status("Setting the default char signedness for new cluster");
|
||||||
|
|
||||||
|
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
|
||||||
|
"\"%s/pg_resetwal\" --char-signedness %s \"%s\"",
|
||||||
|
new_cluster.bindir,
|
||||||
|
new_char_signedness ? "signed" : "unsigned",
|
||||||
|
new_cluster.pgdata);
|
||||||
|
|
||||||
|
check_ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy locale and encoding information into the new cluster's template0.
|
* Copy locale and encoding information into the new cluster's template0.
|
||||||
|
@ -125,6 +125,11 @@ extern char *output_files[];
|
|||||||
*/
|
*/
|
||||||
#define JSONB_FORMAT_CHANGE_CAT_VER 201409291
|
#define JSONB_FORMAT_CHANGE_CAT_VER 201409291
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The control file was changed to have the default char signedness,
|
||||||
|
* commit 44fe30fdab6746a287163e7cc093fd36cda8eb92
|
||||||
|
*/
|
||||||
|
#define DEFAULT_CHAR_SIGNEDNESS_CAT_VER 202502212
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each relation is represented by a relinfo structure.
|
* Each relation is represented by a relinfo structure.
|
||||||
@ -245,6 +250,7 @@ typedef struct
|
|||||||
bool date_is_int;
|
bool date_is_int;
|
||||||
bool float8_pass_by_value;
|
bool float8_pass_by_value;
|
||||||
uint32 data_checksum_version;
|
uint32 data_checksum_version;
|
||||||
|
bool default_char_signedness;
|
||||||
} ControlData;
|
} ControlData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
65
src/bin/pg_upgrade/t/005_char_signedness.pl
Normal file
65
src/bin/pg_upgrade/t/005_char_signedness.pl
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Copyright (c) 2025, PostgreSQL Global Development Group
|
||||||
|
|
||||||
|
# Tests for handling the default char signedness during upgrade.
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings FATAL => 'all';
|
||||||
|
|
||||||
|
use PostgreSQL::Test::Cluster;
|
||||||
|
use PostgreSQL::Test::Utils;
|
||||||
|
use Test::More;
|
||||||
|
|
||||||
|
# Can be changed to test the other modes
|
||||||
|
my $mode = $ENV{PG_TEST_PG_UPGRADE_MODE} || '--copy';
|
||||||
|
|
||||||
|
# Initialize old and new clusters
|
||||||
|
my $old = PostgreSQL::Test::Cluster->new('old');
|
||||||
|
my $new = PostgreSQL::Test::Cluster->new('new');
|
||||||
|
$old->init();
|
||||||
|
$new->init();
|
||||||
|
|
||||||
|
# Check the default char signedness of both the old and the new clusters.
|
||||||
|
# Newly created clusters unconditionally use 'signed'.
|
||||||
|
command_like(
|
||||||
|
[ 'pg_controldata', $old->data_dir ],
|
||||||
|
qr/Default char data signedness:\s+signed/,
|
||||||
|
'default char signedness of old cluster is signed in control file');
|
||||||
|
command_like(
|
||||||
|
[ 'pg_controldata', $new->data_dir ],
|
||||||
|
qr/Default char data signedness:\s+signed/,
|
||||||
|
'default char signedness of new cluster is signed in control file');
|
||||||
|
|
||||||
|
# Set the old cluster's default char signedness to unsigned for test.
|
||||||
|
command_ok(
|
||||||
|
[ 'pg_resetwal', '--char-signedness', 'unsigned', '-f', $old->data_dir ],
|
||||||
|
"set old cluster's default char signedness to unsigned");
|
||||||
|
|
||||||
|
# Check if the value is successfully updated.
|
||||||
|
command_like(
|
||||||
|
[ 'pg_controldata', $old->data_dir ],
|
||||||
|
qr/Default char data signedness:\s+unsigned/,
|
||||||
|
'updated default char signedness is unsigned in control file');
|
||||||
|
|
||||||
|
# pg_upgrade should be successful.
|
||||||
|
command_ok(
|
||||||
|
[
|
||||||
|
'pg_upgrade', '--no-sync',
|
||||||
|
'-d', $old->data_dir,
|
||||||
|
'-D', $new->data_dir,
|
||||||
|
'-b', $old->config_data('--bindir'),
|
||||||
|
'-B', $new->config_data('--bindir'),
|
||||||
|
'-s', $new->host,
|
||||||
|
'-p', $old->port,
|
||||||
|
'-P', $new->port,
|
||||||
|
$mode
|
||||||
|
],
|
||||||
|
'run of pg_upgrade');
|
||||||
|
|
||||||
|
# Check if the default char signedness of the new cluster inherited
|
||||||
|
# the old cluster's value.
|
||||||
|
command_like(
|
||||||
|
[ 'pg_controldata', $new->data_dir ],
|
||||||
|
qr/Default char data signedness:\s+unsigned/,
|
||||||
|
'the default char signedness is updated during pg_upgrade');
|
||||||
|
|
||||||
|
done_testing();
|
Reference in New Issue
Block a user