Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 126 additions & 8 deletions bin/postgresql-setup.in
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,103 @@ initdb()
old_data_in_use()
{
local pidfile="$pgdataold/postmaster.pid"
test -f "$pidfile" || return 1
error $"The pidfile '$pidfile' exists. Verify that there is no postmaster"
error_q $"running the $pgdataold directory."
if [ -f "$pidfile" ]; then
# Check if the PID in the file is actually running
local pid
pid=$(head -n 1 "$pidfile" 2>/dev/null)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
error $"Old cluster server is running (PID: $pid). Verify that there is no postmaster"
error_q $"running in the $pgdataold directory."
else
warn "Old pidfile found but no process uses it. Please remove $pidfile to continue."
fi
exit 1
fi
}


# Detect locale settings from old cluster datadir
# Sets: old_cluster_lc_collate, old_cluster_lc_ctype, old_cluster_locale
detect_old_cluster_locale()
{
local old_datadir="$1"
local old_bindir="$2"
local old_port="$3"

old_cluster_lc_collate=""
old_cluster_lc_ctype=""
old_cluster_locale=""

# Try starting old postgresql server
debug "old cluster server is not running, attempting temporary start to query locale"

# Create a temporary socket directory
local temp_sockdir
temp_sockdir=$(mktemp -d 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$temp_sockdir" ]; then
debug "failed to create temporary socket directory"
return 1
fi

local temp_log="$old_datadir/temp_locale_query.log"

# Try to start server with minimal configuration
# Use a different port to avoid conflicts
local temp_port=$((old_port + 10000))

# Start server in background with minimal settings
# Use -m fast to speed up startup
if "$old_bindir/pg_ctl" -D "$old_datadir" -o "-p $temp_port -c listen_addresses='' -c unix_socket_directories='$temp_sockdir' -c max_connections=5 -c shared_buffers=128kB" start -w -l "$temp_log" -m fast >/dev/null 2>&1; then
debug "temporarily started old cluster server on port $temp_port"
# Give it a moment to be ready
sleep 2
else
debug "failed to start old cluster server temporarily (see $temp_log for details)"
rm -rf "$temp_sockdir"
rm -f "$temp_log"
return 1
fi


# Query locale from template1 database
local query="SELECT datcollate, datctype FROM pg_catalog.pg_database WHERE datname = 'template1'"
local result
local query_port="$temp_port"

# Perform query
local psql_exit_code=0
result=$("$PGENGINE/psql" -t -A -h "$temp_sockdir" -p "$query_port" -d template1 -c "$query" 2>/dev/null)
psql_exit_code=$?

# Stop temporary server
"$old_bindir/pg_ctl" -D "$old_datadir" stop >/dev/null 2>&1
rm -rf "$temp_sockdir"
rm -f "$temp_log"

# Parse result
if [ $psql_exit_code -eq 0 ] && [ -n "$result" ]; then
# Parse result: datcollate|datctype
old_cluster_lc_collate=$(echo "$result" | cut -d'|' -f1 | tr -d ' ')
old_cluster_lc_ctype=$(echo "$result" | cut -d'|' -f2 | tr -d ' ')
old_cluster_locale="$old_cluster_lc_collate"

if [ -n "$old_cluster_lc_collate" ] && [ -n "$old_cluster_lc_ctype" ]; then
debug "detected locale from old cluster: collate=$old_cluster_lc_collate, ctype=$old_cluster_lc_ctype"
return 0
fi
fi

# If we couldn't detect it, return failure
warn $"Could not automatically detect locale settings from old cluster."
warn_q $"You may need to set PGSETUP_INITDB_OPTIONS manually with --lc-collate, --lc-ctype, and --locale options."
return 1
}


upgrade()
{
# Fail fast if there is a postgresql server running using the data to be updated
old_data_in_use
local inplace=false
test "$pgdata" = "$upgradefrom_data" && inplace=true

Expand Down Expand Up @@ -275,6 +364,39 @@ upgrade()

info $"Upgrading database."

# Automatically detect locale settings from old cluster if not already set
# This addresses Bug 1152556: detect --locale from old datadir automatically
local locale_already_set=false
if [ -n "$PGSETUP_INITDB_OPTIONS" ]; then
if echo "$PGSETUP_INITDB_OPTIONS" | grep -qE -- "--lc-collate|--lc-ctype|--locale"; then
locale_already_set=true
fi
fi

if [ "$locale_already_set" != "true" ]; then
debug "attempting to auto-detect locale from old cluster"
if detect_old_cluster_locale "$pgdataold" "$upgradefrom_engine" "$PGPORT"; then
# Build initdb options with detected locale
local detected_opts="--lc-collate=$old_cluster_lc_collate --lc-ctype=$old_cluster_lc_ctype"
if [ -n "$old_cluster_locale" ]; then
detected_opts="$detected_opts --locale=$old_cluster_locale"
fi

# Append to existing PGSETUP_INITDB_OPTIONS if set, otherwise set it
if [ -n "$PGSETUP_INITDB_OPTIONS" ]; then
export PGSETUP_INITDB_OPTIONS="$PGSETUP_INITDB_OPTIONS $detected_opts"
else
export PGSETUP_INITDB_OPTIONS="$detected_opts"
fi

info $"Auto-detected locale settings from old cluster: $detected_opts"
else
debug "locale auto-detection failed, proceeding with system default locale"
fi
else
debug "locale options already set in PGSETUP_INITDB_OPTIONS, skipping auto-detection"
fi

scls_upgrade_hacks=
test -n "$upgradefrom_scls" && {
debug "scls [$upgradefrom_scls] will be enabled"
Expand All @@ -291,11 +413,7 @@ upgrade()
}

local failure_cleanup=true
if old_data_in_use; then
script_result=1
# Cleanup makes sense once perform_initdb gets called.
failure_cleanup=false
elif ! check_not_initialized; then
if ! check_not_initialized; then
# Don't try to re-init initialized data directory and also do not
# remove it after this unsuccessful upgrade.
script_result=1
Expand Down
100 changes: 100 additions & 0 deletions tmt/tests/virtual/sanity/locale-change/locale.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/bin/bash
# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k

. /usr/share/beakerlib/beakerlib.sh || exit 1

rlJournalStart
rlPhaseStartSetup
rlRun "git clone \"$REPO_URL\" repo"
rlRun "pushd repo"
rlRun "git fetch origin \"$PR_HEAD\""
rlRun "git checkout FETCH_HEAD"
rlRun "cat /etc/fedora-release"
rlRun "dnf -y install postgresql16-server"

rlRun "autoreconf -vfi" 0 "Building and installing postgresql-setup"
rlRun "./configure --prefix=/usr"
rlRun "make"
rlRun "./bin/postgresql-setup --init" 0 "Initializing database dir"
rlRun "systemctl start postgresql" 0 "Starting service"
rlRun "systemctl is-active postgresql" 0 "Verifying service running"
rlPhaseEnd

rlPhaseStartTest
rlRun "su - postgres -c \"
createdb testdb;
psql -U postgres -d testdb -c \\\"create table users (id serial primary key, name text)\\\";
psql -U postgres -d testdb -c \\\"insert into users (name) values ('Alice'), ('Bob'), ('Celine')\\\"
\""
rlRun "su - postgres -c '
psql -U postgres -d testdb -c \"select * from users\"
' > expected.txt"

echo "Expected:"
cat expected.txt

# change locale (https://wiki.archlinux.org/title/Locale#Make_locale_changes_immediate)
rlRun "localectl set-locale LANG=en_GB.UTF-8" 0 "Changing locale"
rlRun "unset LANG"
rlRun "source /etc/profile.d/lang.sh"
rlRun "locale"

rlRun "dnf -y remove postgresql16*" 0 "Removing postgresql 16"
rlRun "dnf -y install postgresql17-upgrade" 0 "Installing postgresql 17"
rlRun "./bin/postgresql-setup --upgrade" 0 "Running upgrade"

rlRun "systemctl start postgresql" 0 "Starting service again"
rlRun "systemctl is-active postgresql" 0 "Verifying service running"

rlRun "su - postgres -c '
psql -U postgres -d testdb -c \"select * from users\"
' > actual17.txt"

echo "Actual:"
cat actual17.txt

rlAssertNotDiffer expected.txt actual17.txt

rlRun "localectl set-locale LC_COLLATE=en_US.UTF-8" 0 "Changing LC_COLLATE"
rlRun "localectl set-locale LC_CTYPE=en_AU.UTF-8" 0 "Changing LC_CTYPE"
rlRun "unset LANG"
rlRun "source /etc/profile.d/lang.sh"
rlRun "locale"

rlRun "dnf -y remove postgresql17*" 0 "Removing postgresql 17"
rlRun "dnf -y install postgresql18-upgrade" 0 "Installing postgresql 18"
# TODO: remove if functionality added to the script
rlRun "/usr/lib64/pgsql/postgresql-17/bin/pg_checksums -e /var/lib/pgsql/data" 0 "Enabling data checksums for pg18"

rlRun "su - postgres -c '/usr/lib64/pgsql/postgresql-17/bin/pg_ctl -D /var/lib/pgsql/data -l /var/lib/pgsql/logfile start'" 0 "Starting postgres pre-upgrade"
rlRun "su - postgres -c '/usr/lib64/pgsql/postgresql-17/bin/pg_ctl -D /var/lib/pgsql/data status'" 0 "Verifying postgres is running"

rlRun "./bin/postgresql-setup --upgrade --debug" 1 "Trying to run upgrade"
rlRun "su - postgres -c '/usr/lib64/pgsql/postgresql-17/bin/pg_ctl -D /var/lib/pgsql/data stop'" 0 "Stopping old postgres"
rlRun "./bin/postgresql-setup --upgrade --debug" 0 "Upgrading"

rlRun "systemctl start postgresql" 0 "Starting service again"
rlRun "systemctl is-active postgresql" 0 "Verifying service running"

rlRun "su - postgres -c '
psql -U postgres -d testdb -c \"select * from users\"
' > actual18.txt"

echo "Actual:"
cat actual18.txt

rlAssertNotDiffer actual17.txt actual18.txt
rlPhaseEnd

rlPhaseStartCleanup
rlRun "popd"
rlRun "rm -rf repo"
rlRun "echo 'LANG=en_US.UTF-8' > /etc/locale.conf" 0 "Resetting locale"
rlRun "unset LANG"
rlRun "source /etc/profile.d/lang.sh"
rlRun "systemctl stop postgresql" 0 "Stopping postgresql service"
rlRun "rm -rf /var/lib/pgsql" 0 "Removing database folder"
rlRun "dnf -y remove postgresql*" 0 "Uninstalling postgresql"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd
19 changes: 19 additions & 0 deletions tmt/tests/virtual/sanity/locale-change/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
summary: Check if upgrading a database works when using a different locale
name: locale-change
require:
- make
- m4
- docbook-utils
- help2man
- elinks
- coreutils
- autoconf
- automake
- autoconf-archive
- git
framework: beakerlib
contact: pkhartsk@redhat.com
tag:
- fedora-upgrade
test: ./locale.sh

Loading