diff options
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/modules/injection_points/injection_points.c | 6 | ||||
| -rw-r--r-- | src/test/modules/test_dsa/test_dsa.c | 6 | ||||
| -rw-r--r-- | src/test/modules/test_dsm_registry/test_dsm_registry.c | 7 | ||||
| -rw-r--r-- | src/test/postmaster/t/002_connection_limits.pl | 5 | ||||
| -rw-r--r-- | src/test/postmaster/t/003_start_stop.pl | 7 | ||||
| -rw-r--r-- | src/test/recovery/meson.build | 1 | ||||
| -rw-r--r-- | src/test/recovery/t/050_redo_segment_missing.pl | 117 | ||||
| -rw-r--r-- | src/test/regress/expected/nls.out | 21 | ||||
| -rw-r--r-- | src/test/regress/expected/nls_1.out | 21 | ||||
| -rw-r--r-- | src/test/regress/expected/nls_2.out | 29 | ||||
| -rw-r--r-- | src/test/regress/regress.c | 34 | ||||
| -rw-r--r-- | src/test/regress/sql/nls.sql | 6 |
12 files changed, 211 insertions, 49 deletions
diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c index 417b61f31c5..25340e8d81b 100644 --- a/src/test/modules/injection_points/injection_points.c +++ b/src/test/modules/injection_points/injection_points.c @@ -115,7 +115,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL; * when initializing dynamically with a DSM or when loading the module. */ static void -injection_point_init_state(void *ptr) +injection_point_init_state(void *ptr, void *arg) { InjectionPointSharedState *state = (InjectionPointSharedState *) ptr; @@ -159,7 +159,7 @@ injection_shmem_startup(void) * First time through, so initialize. This is shared with the dynamic * initialization using a DSM. */ - injection_point_init_state(inj_state); + injection_point_init_state(inj_state, NULL); } LWLockRelease(AddinShmemInitLock); @@ -179,7 +179,7 @@ injection_init_shmem(void) inj_state = GetNamedDSMSegment("injection_points", sizeof(InjectionPointSharedState), injection_point_init_state, - &found); + &found, NULL); } /* diff --git a/src/test/modules/test_dsa/test_dsa.c b/src/test/modules/test_dsa/test_dsa.c index 21e4ce6a745..b9c45c0d41c 100644 --- a/src/test/modules/test_dsa/test_dsa.c +++ b/src/test/modules/test_dsa/test_dsa.c @@ -21,7 +21,7 @@ PG_MODULE_MAGIC; static void -init_tranche(void *ptr) +init_tranche(void *ptr, void *arg) { int *tranche_id = (int *) ptr; @@ -39,7 +39,7 @@ test_dsa_basic(PG_FUNCTION_ARGS) dsa_pointer p[100]; tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int), - init_tranche, &found); + init_tranche, &found, NULL); a = dsa_create(*tranche_id); for (int i = 0; i < 100; i++) @@ -80,7 +80,7 @@ test_dsa_resowners(PG_FUNCTION_ARGS) ResourceOwner childowner; tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int), - init_tranche, &found); + init_tranche, &found, NULL); /* Create DSA in parent resource owner */ a = dsa_create(*tranche_id); diff --git a/src/test/modules/test_dsm_registry/test_dsm_registry.c b/src/test/modules/test_dsm_registry/test_dsm_registry.c index 4cc2ccdac3f..3e5f4f3cda1 100644 --- a/src/test/modules/test_dsm_registry/test_dsm_registry.c +++ b/src/test/modules/test_dsm_registry/test_dsm_registry.c @@ -44,10 +44,13 @@ static const dshash_parameters dsh_params = { }; static void -init_tdr_dsm(void *ptr) +init_tdr_dsm(void *ptr, void *arg) { TestDSMRegistryStruct *dsm = (TestDSMRegistryStruct *) ptr; + if ((int) (intptr_t) arg != 5432) + elog(ERROR, "unexpected arg value %d", (int) (intptr_t) arg); + LWLockInitialize(&dsm->lck, LWLockNewTrancheId("test_dsm_registry")); dsm->val = 0; } @@ -60,7 +63,7 @@ tdr_attach_shmem(void) tdr_dsm = GetNamedDSMSegment("test_dsm_registry_dsm", sizeof(TestDSMRegistryStruct), init_tdr_dsm, - &found); + &found, (void *) (intptr_t) 5432); if (tdr_dsa == NULL) tdr_dsa = GetNamedDSA("test_dsm_registry_dsa", &found); diff --git a/src/test/postmaster/t/002_connection_limits.pl b/src/test/postmaster/t/002_connection_limits.pl index 4a7fb16261f..2fc821ad0b4 100644 --- a/src/test/postmaster/t/002_connection_limits.pl +++ b/src/test/postmaster/t/002_connection_limits.pl @@ -74,6 +74,11 @@ sub connect_fails_wait ok(1, "$test_name: client backend process exited"); } +# Restart the server to ensure that any backends launched for the +# initialization steps are gone. Otherwise they could still be using +# up connection slots and mess with our expectations. +$node->restart; + my @sessions = (); my @raw_connections = (); diff --git a/src/test/postmaster/t/003_start_stop.pl b/src/test/postmaster/t/003_start_stop.pl index 58e7ba6cc42..25d6f667217 100644 --- a/src/test/postmaster/t/003_start_stop.pl +++ b/src/test/postmaster/t/003_start_stop.pl @@ -46,6 +46,11 @@ if (!$node->raw_connect_works()) plan skip_all => "this test requires working raw_connect()"; } +# Restart the server to ensure that the backend launched for +# raw_connect_works() is gone. Otherwise, it might free up the +# connection slot later, when we expect all the slots to be in use. +$node->restart; + my @raw_connections = (); # Open a lot of TCP (or Unix domain socket) connections to use up all @@ -81,7 +86,7 @@ for (my $i = 0; $i <= 20; $i++) # clients already" instead of "role does not exist" error. Test that # to ensure that we have used up all the slots. $node->connect_fails("dbname=postgres user=invalid_user", - "connect ", + "connection is rejected when all slots are in use", expected_stderr => qr/FATAL: sorry, too many clients already/); # Open one more connection, to really ensure that we have at least one diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build index 523a5cd5b52..e93248bd66e 100644 --- a/src/test/recovery/meson.build +++ b/src/test/recovery/meson.build @@ -58,6 +58,7 @@ tests += { 't/047_checkpoint_physical_slot.pl', 't/048_vacuum_horizon_floor.pl', 't/049_wait_for_lsn.pl', + 't/050_redo_segment_missing.pl', ], }, } diff --git a/src/test/recovery/t/050_redo_segment_missing.pl b/src/test/recovery/t/050_redo_segment_missing.pl new file mode 100644 index 00000000000..f5eb6c30fe6 --- /dev/null +++ b/src/test/recovery/t/050_redo_segment_missing.pl @@ -0,0 +1,117 @@ +# Copyright (c) 2025, PostgreSQL Global Development Group +# +# Evaluates PostgreSQL's recovery behavior when a WAL segment containing the +# redo record is missing, with a checkpoint record located in a different +# segment. + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +if ($ENV{enable_injection_points} ne 'yes') +{ + plan skip_all => 'Injection points not supported by this build'; +} + +my $node = PostgreSQL::Test::Cluster->new('testnode'); +$node->init; +$node->append_conf('postgresql.conf', 'log_checkpoints = on'); +$node->start; + +# Check if the extension injection_points is available, as it may be +# possible that this script is run with installcheck, where the module +# would not be installed by default. +if (!$node->check_extension('injection_points')) +{ + plan skip_all => 'Extension injection_points not installed'; +} +$node->safe_psql('postgres', q(CREATE EXTENSION injection_points)); + +# Note that this uses two injection points based on waits, not one. This +# may look strange, but this works as a workaround to enforce all memory +# allocations to happen outside the critical section of the checkpoint +# required for this test. +# First, "create-checkpoint-initial" is run outside the critical section +# section, and is used as a way to initialize the shared memory required +# for the wait machinery with its DSM registry. +# Then, "create-checkpoint-run" is loaded outside the critical section of +# a checkpoint to allocate any memory required by the library load, and +# its callback is run inside the critical section. +$node->safe_psql('postgres', + q{select injection_points_attach('create-checkpoint-initial', 'wait')}); +$node->safe_psql('postgres', + q{select injection_points_attach('create-checkpoint-run', 'wait')}); + +# Start a psql session to run the checkpoint in the background and make +# the test wait on the injection point so the checkpoint stops just after +# it starts. +my $checkpoint = $node->background_psql('postgres'); +$checkpoint->query_until( + qr/starting_checkpoint/, + q(\echo starting_checkpoint +checkpoint; +)); + +# Wait for the initial point to finish, the checkpointer is still +# outside its critical section. Then release to reach the second +# point. +$node->wait_for_event('checkpointer', 'create-checkpoint-initial'); +$node->safe_psql('postgres', + q{select injection_points_wakeup('create-checkpoint-initial')}); + +# Wait until the checkpoint has reached the second injection point. +# We are now in the middle of a checkpoint running, after the redo +# record has been logged. +$node->wait_for_event('checkpointer', 'create-checkpoint-run'); + +# Switch the WAL segment, ensuring that the redo record will be included +# in a different segment than the checkpoint record. +$node->safe_psql('postgres', 'SELECT pg_switch_wal()'); + +# Continue the checkpoint and wait for its completion. +my $log_offset = -s $node->logfile; +$node->safe_psql('postgres', + q{select injection_points_wakeup('create-checkpoint-run')}); +$node->wait_for_log(qr/checkpoint complete/, $log_offset); + +$checkpoint->quit; + +# Retrieve the WAL file names for the redo record and checkpoint record. +my $redo_lsn = $node->safe_psql('postgres', + "SELECT redo_lsn FROM pg_control_checkpoint()"); +my $redo_walfile_name = + $node->safe_psql('postgres', "SELECT pg_walfile_name('$redo_lsn')"); +my $checkpoint_lsn = $node->safe_psql('postgres', + "SELECT checkpoint_lsn FROM pg_control_checkpoint()"); +my $checkpoint_walfile_name = + $node->safe_psql('postgres', "SELECT pg_walfile_name('$checkpoint_lsn')"); + +# Redo record and checkpoint record should be on different segments. +isnt($redo_walfile_name, $checkpoint_walfile_name, + 'redo and checkpoint records on different segments'); + +# Remove the WAL segment containing the redo record. +unlink $node->data_dir . "/pg_wal/$redo_walfile_name" + or die "could not remove WAL file: $!"; + +$node->stop('immediate'); + +# Use run_log instead of node->start because this test expects that +# the server ends with an error during recovery. +run_log( + [ + 'pg_ctl', + '--pgdata' => $node->data_dir, + '--log' => $node->logfile, + 'start', + ]); + +# Confirm that recovery has failed, as expected. +my $logfile = slurp_file($node->logfile()); +ok( $logfile =~ + qr/FATAL: .* could not find redo location .* referenced by checkpoint record at .*/, + "ends with FATAL because it could not find redo location"); + +done_testing(); diff --git a/src/test/regress/expected/nls.out b/src/test/regress/expected/nls.out index 2bc795fc822..465d8c7d0be 100644 --- a/src/test/regress/expected/nls.out +++ b/src/test/regress/expected/nls.out @@ -28,27 +28,22 @@ begin raise log 'NLS regression test: lc_messages = %', current_setting('lc_messages'); end $$; -SELECT current_setting('lc_messages') = 'C' AS failed \gset -\if :failed -\echo Could not find an acceptable spelling of es_ES locale -\quit -\endif SELECT test_translation(); NOTICE: traducido PRId64 = 424242424242 NOTICE: traducido PRId32 = -1234 -NOTICE: traducido PRIdMAX = -5678 -NOTICE: traducido PRIdPTR = 9999 +NOTICE: traducido PRIdMAX = -123456789012 +NOTICE: traducido PRIdPTR = -9999 NOTICE: traducido PRIu64 = 424242424242 -NOTICE: traducido PRIu32 = 1234 -NOTICE: traducido PRIuMAX = 5678 +NOTICE: traducido PRIu32 = 4294966062 +NOTICE: traducido PRIuMAX = 123456789012 NOTICE: traducido PRIuPTR = 9999 NOTICE: traducido PRIx64 = 62c6d1a9b2 -NOTICE: traducido PRIx32 = 4d2 -NOTICE: traducido PRIxMAX = 162e +NOTICE: traducido PRIx32 = fffffb2e +NOTICE: traducido PRIxMAX = 1cbe991a14 NOTICE: traducido PRIxPTR = 270f NOTICE: traducido PRIX64 = 62C6D1A9B2 -NOTICE: traducido PRIX32 = 4D2 -NOTICE: traducido PRIXMAX = 162E +NOTICE: traducido PRIX32 = FFFFFB2E +NOTICE: traducido PRIXMAX = 1CBE991A14 NOTICE: traducido PRIXPTR = 270F test_translation ------------------ diff --git a/src/test/regress/expected/nls_1.out b/src/test/regress/expected/nls_1.out index 3117fa21ae0..1498aa62111 100644 --- a/src/test/regress/expected/nls_1.out +++ b/src/test/regress/expected/nls_1.out @@ -28,13 +28,24 @@ begin raise log 'NLS regression test: lc_messages = %', current_setting('lc_messages'); end $$; -SELECT current_setting('lc_messages') = 'C' AS failed \gset -\if :failed -\echo Could not find an acceptable spelling of es_ES locale -\quit -\endif SELECT test_translation(); NOTICE: NLS is not enabled +NOTICE: translated PRId64 = 424242424242 +NOTICE: translated PRId32 = -1234 +NOTICE: translated PRIdMAX = -123456789012 +NOTICE: translated PRIdPTR = -9999 +NOTICE: translated PRIu64 = 424242424242 +NOTICE: translated PRIu32 = 4294966062 +NOTICE: translated PRIuMAX = 123456789012 +NOTICE: translated PRIuPTR = 9999 +NOTICE: translated PRIx64 = 62c6d1a9b2 +NOTICE: translated PRIx32 = fffffb2e +NOTICE: translated PRIxMAX = 1cbe991a14 +NOTICE: translated PRIxPTR = 270f +NOTICE: translated PRIX64 = 62C6D1A9B2 +NOTICE: translated PRIX32 = FFFFFB2E +NOTICE: translated PRIXMAX = 1CBE991A14 +NOTICE: translated PRIXPTR = 270F test_translation ------------------ diff --git a/src/test/regress/expected/nls_2.out b/src/test/regress/expected/nls_2.out index cb8e4b59d16..54852a39925 100644 --- a/src/test/regress/expected/nls_2.out +++ b/src/test/regress/expected/nls_2.out @@ -28,8 +28,27 @@ begin raise log 'NLS regression test: lc_messages = %', current_setting('lc_messages'); end $$; -SELECT current_setting('lc_messages') = 'C' AS failed \gset -\if :failed -\echo Could not find an acceptable spelling of es_ES locale -Could not find an acceptable spelling of es_ES locale -\quit +SELECT test_translation(); +NOTICE: lc_messages is 'C' +NOTICE: translated PRId64 = 424242424242 +NOTICE: translated PRId32 = -1234 +NOTICE: translated PRIdMAX = -123456789012 +NOTICE: translated PRIdPTR = -9999 +NOTICE: translated PRIu64 = 424242424242 +NOTICE: translated PRIu32 = 4294966062 +NOTICE: translated PRIuMAX = 123456789012 +NOTICE: translated PRIuPTR = 9999 +NOTICE: translated PRIx64 = 62c6d1a9b2 +NOTICE: translated PRIx32 = fffffb2e +NOTICE: translated PRIxMAX = 1cbe991a14 +NOTICE: translated PRIxPTR = 270f +NOTICE: translated PRIX64 = 62C6D1A9B2 +NOTICE: translated PRIX32 = FFFFFB2E +NOTICE: translated PRIXMAX = 1CBE991A14 +NOTICE: translated PRIXPTR = 270F + test_translation +------------------ + +(1 row) + +RESET lc_messages; diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index 26ae0a6c787..acac34d40b9 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -1156,6 +1156,10 @@ test_relpath(PG_FUNCTION_ARGS) /* * Simple test to verify NLS support, particularly that the PRI* macros work. + * + * A secondary objective is to verify that <inttypes.h>'s values for the + * PRI* macros match what our snprintf.c code will do. Therefore, we run + * the ereport() calls even when we know that translation will not happen. */ PG_FUNCTION_INFO_V1(test_translation); Datum @@ -1185,44 +1189,52 @@ test_translation(PG_FUNCTION_ARGS) inited = true; } + /* + * If nls.sql failed to select a non-C locale, no translation will happen. + * Report that so that we can distinguish this outcome from brokenness. + * (We do this here, not in nls.sql, so as to need only 3 expected files.) + */ + if (strcmp(GetConfigOption("lc_messages", false, false), "C") == 0) + elog(NOTICE, "lc_messages is 'C'"); +#else + elog(NOTICE, "NLS is not enabled"); +#endif + ereport(NOTICE, errmsg("translated PRId64 = %" PRId64, (int64) 424242424242)); ereport(NOTICE, errmsg("translated PRId32 = %" PRId32, (int32) -1234)); ereport(NOTICE, - errmsg("translated PRIdMAX = %" PRIdMAX, (intmax_t) -5678)); + errmsg("translated PRIdMAX = %" PRIdMAX, (intmax_t) -123456789012)); ereport(NOTICE, - errmsg("translated PRIdPTR = %" PRIdPTR, (intptr_t) 9999)); + errmsg("translated PRIdPTR = %" PRIdPTR, (intptr_t) -9999)); ereport(NOTICE, errmsg("translated PRIu64 = %" PRIu64, (uint64) 424242424242)); ereport(NOTICE, - errmsg("translated PRIu32 = %" PRIu32, (uint32) 1234)); + errmsg("translated PRIu32 = %" PRIu32, (uint32) -1234)); ereport(NOTICE, - errmsg("translated PRIuMAX = %" PRIuMAX, (uintmax_t) 5678)); + errmsg("translated PRIuMAX = %" PRIuMAX, (uintmax_t) 123456789012)); ereport(NOTICE, errmsg("translated PRIuPTR = %" PRIuPTR, (uintptr_t) 9999)); ereport(NOTICE, errmsg("translated PRIx64 = %" PRIx64, (uint64) 424242424242)); ereport(NOTICE, - errmsg("translated PRIx32 = %" PRIx32, (uint32) 1234)); + errmsg("translated PRIx32 = %" PRIx32, (uint32) -1234)); ereport(NOTICE, - errmsg("translated PRIxMAX = %" PRIxMAX, (uintmax_t) 5678)); + errmsg("translated PRIxMAX = %" PRIxMAX, (uintmax_t) 123456789012)); ereport(NOTICE, errmsg("translated PRIxPTR = %" PRIxPTR, (uintptr_t) 9999)); ereport(NOTICE, errmsg("translated PRIX64 = %" PRIX64, (uint64) 424242424242)); ereport(NOTICE, - errmsg("translated PRIX32 = %" PRIX32, (uint32) 1234)); + errmsg("translated PRIX32 = %" PRIX32, (uint32) -1234)); ereport(NOTICE, - errmsg("translated PRIXMAX = %" PRIXMAX, (uintmax_t) 5678)); + errmsg("translated PRIXMAX = %" PRIXMAX, (uintmax_t) 123456789012)); ereport(NOTICE, errmsg("translated PRIXPTR = %" PRIXPTR, (uintptr_t) 9999)); -#else - elog(NOTICE, "NLS is not enabled"); -#endif PG_RETURN_VOID(); } diff --git a/src/test/regress/sql/nls.sql b/src/test/regress/sql/nls.sql index 9c605af2f0b..4433a1fd036 100644 --- a/src/test/regress/sql/nls.sql +++ b/src/test/regress/sql/nls.sql @@ -33,12 +33,6 @@ begin current_setting('lc_messages'); end $$; -SELECT current_setting('lc_messages') = 'C' AS failed \gset -\if :failed -\echo Could not find an acceptable spelling of es_ES locale -\quit -\endif - SELECT test_translation(); RESET lc_messages; |
