Skip to content

Commit a8238f8

Browse files
pg_upgrade: Preserve default char signedness value from old cluster.
Commit 44fe30f 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
1 parent 30666d1 commit a8238f8

File tree

4 files changed

+142
-1
lines changed

4 files changed

+142
-1
lines changed

src/bin/pg_upgrade/controldata.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "postgres_fe.h"
1111

1212
#include <ctype.h>
13+
#include <limits.h> /* for CHAR_MIN */
1314

1415
#include "common/string.h"
1516
#include "pg_upgrade.h"
@@ -62,6 +63,7 @@ get_control_data(ClusterInfo *cluster)
6263
bool got_date_is_int = false;
6364
bool got_data_checksum_version = false;
6465
bool got_cluster_state = false;
66+
bool got_default_char_signedness = false;
6567
char *lc_collate = NULL;
6668
char *lc_ctype = NULL;
6769
char *lc_monetary = NULL;
@@ -501,6 +503,25 @@ get_control_data(ClusterInfo *cluster)
501503
cluster->controldata.data_checksum_version = str2uint(p);
502504
got_data_checksum_version = true;
503505
}
506+
else if ((p = strstr(bufin, "Default char data signedness:")) != NULL)
507+
{
508+
p = strchr(p, ':');
509+
510+
if (p == NULL || strlen(p) <= 1)
511+
pg_fatal("%d: controldata retrieval problem", __LINE__);
512+
513+
/* Skip the colon and any whitespace after it */
514+
p++;
515+
while (isspace((unsigned char) *p))
516+
p++;
517+
518+
/* The value should be either 'signed' or 'unsigned' */
519+
if (strcmp(p, "signed") != 0 && strcmp(p, "unsigned") != 0)
520+
pg_fatal("%d: controldata retrieval problem", __LINE__);
521+
522+
cluster->controldata.default_char_signedness = strcmp(p, "signed") == 0;
523+
got_default_char_signedness = true;
524+
}
504525
}
505526

506527
rc = pclose(output);
@@ -561,6 +582,21 @@ get_control_data(ClusterInfo *cluster)
561582
}
562583
}
563584

585+
/*
586+
* Pre-v18 database clusters don't have the default char signedness
587+
* information. We use the char signedness of the platform where
588+
* pg_upgrade was built.
589+
*/
590+
if (cluster->controldata.cat_ver < DEFAULT_CHAR_SIGNEDNESS_CAT_VER)
591+
{
592+
Assert(!got_default_char_signedness);
593+
#if CHAR_MIN != 0
594+
cluster->controldata.default_char_signedness = true;
595+
#else
596+
cluster->controldata.default_char_signedness = false;
597+
#endif
598+
}
599+
564600
/* verify that we got all the mandatory pg_control data */
565601
if (!got_xid || !got_oid ||
566602
!got_multi || !got_oldestxid ||
@@ -572,7 +608,9 @@ get_control_data(ClusterInfo *cluster)
572608
!got_index || !got_toast ||
573609
(!got_large_object &&
574610
cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) ||
575-
!got_date_is_int || !got_data_checksum_version)
611+
!got_date_is_int || !got_data_checksum_version ||
612+
(!got_default_char_signedness &&
613+
cluster->controldata.cat_ver >= DEFAULT_CHAR_SIGNEDNESS_CAT_VER))
576614
{
577615
if (cluster == &old_cluster)
578616
pg_log(PG_REPORT,
@@ -641,6 +679,10 @@ get_control_data(ClusterInfo *cluster)
641679
if (!got_data_checksum_version)
642680
pg_log(PG_REPORT, " data checksum version");
643681

682+
/* value added in Postgres 18 */
683+
if (!got_default_char_signedness)
684+
pg_log(PG_REPORT, " default char signedness");
685+
644686
pg_fatal("Cannot continue without required control information, terminating");
645687
}
646688
}

src/bin/pg_upgrade/pg_upgrade.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
*/
5555
#define RESTORE_TRANSACTION_SIZE 1000
5656

57+
static void set_new_cluster_char_signedness(void);
5758
static void set_locale_and_encoding(void);
5859
static void prepare_new_cluster(void);
5960
static void prepare_new_globals(void);
@@ -154,6 +155,7 @@ main(int argc, char **argv)
154155
*/
155156

156157
copy_xact_xlog_xid();
158+
set_new_cluster_char_signedness();
157159

158160
/* New now using xids of the old system */
159161

@@ -388,6 +390,32 @@ setup(char *argv0)
388390
}
389391
}
390392

393+
/*
394+
* Set the new cluster's default char signedness using the old cluster's
395+
* value.
396+
*/
397+
static void
398+
set_new_cluster_char_signedness(void)
399+
{
400+
bool new_char_signedness;
401+
402+
/* Inherit the source database's signedness */
403+
new_char_signedness = old_cluster.controldata.default_char_signedness;
404+
405+
/* Change the char signedness of the new cluster, if necessary */
406+
if (new_cluster.controldata.default_char_signedness != new_char_signedness)
407+
{
408+
prep_status("Setting the default char signedness for new cluster");
409+
410+
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
411+
"\"%s/pg_resetwal\" --char-signedness %s \"%s\"",
412+
new_cluster.bindir,
413+
new_char_signedness ? "signed" : "unsigned",
414+
new_cluster.pgdata);
415+
416+
check_ok();
417+
}
418+
}
391419

392420
/*
393421
* Copy locale and encoding information into the new cluster's template0.

src/bin/pg_upgrade/pg_upgrade.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ extern char *output_files[];
125125
*/
126126
#define JSONB_FORMAT_CHANGE_CAT_VER 201409291
127127

128+
/*
129+
* The control file was changed to have the default char signedness,
130+
* commit 44fe30fdab6746a287163e7cc093fd36cda8eb92
131+
*/
132+
#define DEFAULT_CHAR_SIGNEDNESS_CAT_VER 202502212
128133

129134
/*
130135
* Each relation is represented by a relinfo structure.
@@ -245,6 +250,7 @@ typedef struct
245250
bool date_is_int;
246251
bool float8_pass_by_value;
247252
uint32 data_checksum_version;
253+
bool default_char_signedness;
248254
} ControlData;
249255

250256
/*
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright (c) 2025, PostgreSQL Global Development Group
2+
3+
# Tests for handling the default char signedness during upgrade.
4+
5+
use strict;
6+
use warnings FATAL => 'all';
7+
8+
use PostgreSQL::Test::Cluster;
9+
use PostgreSQL::Test::Utils;
10+
use Test::More;
11+
12+
# Can be changed to test the other modes
13+
my $mode = $ENV{PG_TEST_PG_UPGRADE_MODE} || '--copy';
14+
15+
# Initialize old and new clusters
16+
my $old = PostgreSQL::Test::Cluster->new('old');
17+
my $new = PostgreSQL::Test::Cluster->new('new');
18+
$old->init();
19+
$new->init();
20+
21+
# Check the default char signedness of both the old and the new clusters.
22+
# Newly created clusters unconditionally use 'signed'.
23+
command_like(
24+
[ 'pg_controldata', $old->data_dir ],
25+
qr/Default char data signedness:\s+signed/,
26+
'default char signedness of old cluster is signed in control file');
27+
command_like(
28+
[ 'pg_controldata', $new->data_dir ],
29+
qr/Default char data signedness:\s+signed/,
30+
'default char signedness of new cluster is signed in control file');
31+
32+
# Set the old cluster's default char signedness to unsigned for test.
33+
command_ok(
34+
[ 'pg_resetwal', '--char-signedness', 'unsigned', '-f', $old->data_dir ],
35+
"set old cluster's default char signedness to unsigned");
36+
37+
# Check if the value is successfully updated.
38+
command_like(
39+
[ 'pg_controldata', $old->data_dir ],
40+
qr/Default char data signedness:\s+unsigned/,
41+
'updated default char signedness is unsigned in control file');
42+
43+
# pg_upgrade should be successful.
44+
command_ok(
45+
[
46+
'pg_upgrade', '--no-sync',
47+
'-d', $old->data_dir,
48+
'-D', $new->data_dir,
49+
'-b', $old->config_data('--bindir'),
50+
'-B', $new->config_data('--bindir'),
51+
'-s', $new->host,
52+
'-p', $old->port,
53+
'-P', $new->port,
54+
$mode
55+
],
56+
'run of pg_upgrade');
57+
58+
# Check if the default char signedness of the new cluster inherited
59+
# the old cluster's value.
60+
command_like(
61+
[ 'pg_controldata', $new->data_dir ],
62+
qr/Default char data signedness:\s+unsigned/,
63+
'the default char signedness is updated during pg_upgrade');
64+
65+
done_testing();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy