Compare commits

...

8 Commits

Author SHA1 Message Date
David Rowley
87027cb55b Clarify the 'rows' parameter in create_append_path
This is extracted from a larger patch to improve the UNION planner.
While working on that, I found myself having to check what the 'rows'
parameter is for.  It's not obvious that passing a negative number is the
way to have the rows estimate calculated and to find that out you need
to read code in create_append_path() and in cost_append().

Discussion: https://postgr.es/m/CAApHDvpb_63XQodmxKUF8vb9M7CxyUyT4sWvEgqeQU-GB7QFoQ@mail.gmail.com
2024-02-15 13:13:31 +13:00
Nathan Bossart
8fd0498de2 Remove obsolete check in SIGTERM handler for the startup process.
Thanks to commit 3b00fdba9f, this check in the SIGTERM handler for
the startup process is now obsolete and can be removed.  Instead of
leaving around the dead function write_stderr_signal_safe(), I've
opted to just remove it for now.

This partially reverts commit 97550c0711.

Reviewed-by: Andres Freund, Noah Misch
Discussion: https://postgr.es/m/20231121212008.GA3742740%40nathanxps13
2024-02-14 17:09:31 -06:00
Nathan Bossart
28e4632509 Centralize logic for restoring errno in signal handlers.
Presently, we rely on each individual signal handler to save the
initial value of errno and then restore it before returning if
needed.  This is easily forgotten and, if missed, often goes
undetected for a long time.

In commit 3b00fdba9f, we introduced a wrapper signal handler
function that checks whether MyProcPid matches getpid().  This
commit moves the aforementioned errno restoration code from the
individual signal handlers to the new wrapper handler so that we no
longer need to worry about missing it.

Reviewed-by: Andres Freund, Noah Misch
Discussion: https://postgr.es/m/20231121212008.GA3742740%40nathanxps13
2024-02-14 16:34:18 -06:00
Nathan Bossart
3b00fdba9f Check that MyProcPid == getpid() in backend signal handlers.
In commit 97550c0711, we added a similar check to the SIGTERM
handler for the startup process.  This commit adds this check to
backend signal handlers installed with pqsignal().  This is done by
using a wrapper function that performs the check before calling the
actual handler.

The hope is that this will offer more general protection against
child processes of Postgres backends inadvertently modifying shared
memory due to inherited signal handlers.  Another potential
follow-up improvement is to use this wrapper handler function to
restore errno instead of relying on each individual handler
function to do so.

This commit makes the changes in commit 97550c0711 obsolete but
leaves reverting it for a follow-up commit.

Reviewed-by: Andres Freund, Noah Misch
Discussion: https://postgr.es/m/20231121212008.GA3742740%40nathanxps13
2024-02-14 14:52:14 -06:00
Nathan Bossart
8d8afd48d3 Allow pg_monitor to execute pg_current_logfile().
We allow roles with privileges of pg_monitor to execute functions
like pg_ls_logdir(), so it seems natural that such roles would also
be able to execute this function.

Bumps catversion.

Co-authored-by: Pavlo Golub
Reviewed-by: Daniel Gustafsson
Discussion: https://postgr.es/m/CAK7ymcLmEYWyQkiCZ64WC-HCzXAB0omM%3DYpj9B3rXe8vUAFMqw%40mail.gmail.com
2024-02-14 11:48:29 -06:00
Tom Lane
3e8235ba4f Fix multiranges to behave more like dependent types.
For most purposes, multiranges act like dependent objects of the
associated range type: you can't create them separately or drop them
separately.  This is like the way that autogenerated array types
behave.  However, a couple of points were overlooked: array types
automatically track the ownership of their base type, and array types
do not have their own permissions but use those of the base type,
while multiranges didn't emulate those behaviors.  This is fairly
broken, mainly because pg_dump doesn't think it needs to worry about
multiranges as separate objects, and thus it fails to dump/restore
ownership or permissions of multiranges.

There's no apparent value in letting a multirange diverge from
its parent's ownership or permissions, so let's make them act like
arrays in these respects.  However, we continue to let multiranges
be renamed or moved to a different schema independently of their
parent, since that doesn't break anything.

Discussion: https://postgr.es/m/1580383.1705343264@sss.pgh.pa.us
2024-02-14 11:30:39 -05:00
Amit Kapila
bd8fc1677b Fix BF introduced in commit ddd5f4f54a.
The failure is that the remote slot is not synchronized after the same
slot on standby gets invalidated. The reason was that remote_slot's
restart_lsn was lagged behind the standby's oldest WAL segment. The test
didn't ensure that remote_slot's LSN was advanced to the latest position
before we tried to sync the slots via new the function
pg_sync_replication_slots().

Discussion: https://postgr.es/m/CAA4eK1JLBi3HzenB6do3_hd78kN0UDD1mz-vumWE52XHHEq5Bw@mail.gmail.com
2024-02-14 16:16:08 +05:30
Daniel Gustafsson
b8f9e77725 doc: Remove links to further reading from pgcrypto docs
The pgcrypto docs contained a set of links for useful reading and
technical references. These sets of links were however not actively
curated and had stale content and dead links. Rather than investing
time into maintining these, this removes them altogether since there
are lots of resources online which are actively maintained.

Backpatch to all supported versions since these links have been in
the docs for a long time.

Reported-by: Hanefi Onaldi <hanefi.onaldi@microsoft.com>
Reviewed-by: Magnus Hagander <magnus@hagander.net>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/170774255387.3279713.2822272755998870925@wrigleys.postgresql.org
Backpatch-through: v12
2024-02-14 11:05:10 +01:00
32 changed files with 300 additions and 231 deletions

View File

@ -23735,6 +23735,11 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
<xref linkend="guc-log-destination"/>.
The result reflects the contents of
the <filename>current_logfiles</filename> file.
</para>
<para>
This function is restricted to superusers and roles with privileges of
the <literal>pg_monitor</literal> role by default, but other users can
be granted EXECUTE to run the function.
</para></entry>
</row>

View File

@ -1220,72 +1220,6 @@ gen_random_uuid() returns uuid
ciphertexts of a given size.
</para>
</sect3>
<sect3 id="pgcrypto-notes-useful-reading">
<title>Useful Reading</title>
<itemizedlist>
<listitem>
<para><ulink url="https://www.gnupg.org/gph/en/manual.html"></ulink></para>
<para>The GNU Privacy Handbook.</para>
</listitem>
<listitem>
<para><ulink url="https://www.openwall.com/crypt/"></ulink></para>
<para>Describes the crypt-blowfish algorithm.</para>
</listitem>
<listitem>
<para>
<ulink url="https://www.iusmentis.com/security/passphrasefaq/"></ulink>
</para>
<para>How to choose a good password.</para>
</listitem>
<listitem>
<para><ulink url="http://world.std.com/~reinhold/diceware.html"></ulink></para>
<para>Interesting idea for picking passwords.</para>
</listitem>
<listitem>
<para>
<ulink url="http://www.interhack.net/people/cmcurtin/snake-oil-faq.html"></ulink>
</para>
<para>Describes good and bad cryptography.</para>
</listitem>
</itemizedlist>
</sect3>
<sect3 id="pgcrypto-notes-tech-ref">
<title>Technical References</title>
<itemizedlist>
<listitem>
<para><ulink url="https://tools.ietf.org/html/rfc4880"></ulink></para>
<para>OpenPGP message format.</para>
</listitem>
<listitem>
<para><ulink url="https://tools.ietf.org/html/rfc1321"></ulink></para>
<para>The MD5 Message-Digest Algorithm.</para>
</listitem>
<listitem>
<para><ulink url="https://tools.ietf.org/html/rfc2104"></ulink></para>
<para>HMAC: Keyed-Hashing for Message Authentication.</para>
</listitem>
<listitem>
<para>
<ulink url="https://www.usenix.org/legacy/events/usenix99/provos.html"></ulink>
</para>
<para>Comparison of crypt-des, crypt-md5 and bcrypt algorithms.</para>
</listitem>
<listitem>
<para>
<ulink url="https://en.wikipedia.org/wiki/Fortuna_(PRNG)"></ulink>
</para>
<para>Description of Fortuna CSPRNG.</para>
</listitem>
<listitem>
<para><ulink url="https://jlcooke.ca/random/"></ulink></para>
<para>Jean-Luc Cooke Fortuna-based <filename>/dev/random</filename> driver for Linux.</para>
</listitem>
</itemizedlist>
</sect3>
</sect2>
<sect2 id="pgcrypto-author">

View File

@ -1007,18 +1007,10 @@ MemoryContextSwitchTo(MemoryContext context)
static void
handle_sighup(SIGNAL_ARGS)
{
int save_errno = errno;
got_SIGHUP = true;
SetLatch(MyLatch);
errno = save_errno;
}
</programlisting>
<varname>errno</varname> is saved and restored because
<function>SetLatch()</function> might change it. If that were not done
interrupted code that's currently inspecting <varname>errno</varname> might see the wrong
value.
</para>
</simplesect>

View File

@ -2447,11 +2447,17 @@ ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
/* Disallow GRANT on dependent types */
if (IsTrueArrayType(pg_type_tuple))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("cannot set privileges of array types"),
errhint("Set the privileges of the element type instead.")));
if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("cannot set privileges of multirange types"),
errhint("Set the privileges of the range type instead.")));
/* Used GRANT DOMAIN on a non-domain? */
if (istmt->objtype == OBJECT_DOMAIN &&
@ -3806,6 +3812,35 @@ pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
typeForm = (Form_pg_type) GETSTRUCT(tuple);
}
/*
* Likewise, multirange types don't manage their own permissions; consult
* the associated range type. (Note we must do this after the array step
* to get the right answer for arrays of multiranges.)
*/
if (typeForm->typtype == TYPTYPE_MULTIRANGE)
{
Oid rangetype = get_multirange_range(typeForm->oid);
ReleaseSysCache(tuple);
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
if (!HeapTupleIsValid(tuple))
{
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return 0;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type with OID %u does not exist",
rangetype)));
}
typeForm = (Form_pg_type) GETSTRUCT(tuple);
}
/*
* Now get the type's owner and ACL from the tuple
*/

View File

@ -326,14 +326,15 @@ TypeCreate(Oid newTypeOid,
errmsg("fixed-size types must have storage PLAIN")));
/*
* This is a dependent type if it's an implicitly-created array type, or
* if it's a relation rowtype that's not a composite type. For such types
* we'll leave the ACL empty, and we'll skip creating some dependency
* records because there will be a dependency already through the
* depended-on type or relation. (Caution: this is closely intertwined
* with some behavior in GenerateTypeDependencies.)
* This is a dependent type if it's an implicitly-created array type or
* multirange type, or if it's a relation rowtype that's not a composite
* type. For such types we'll leave the ACL empty, and we'll skip
* creating some dependency records because there will be a dependency
* already through the depended-on type or relation. (Caution: this is
* closely intertwined with some behavior in GenerateTypeDependencies.)
*/
isDependentType = isImplicitArray ||
typeType == TYPTYPE_MULTIRANGE ||
(OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
/*
@ -534,8 +535,9 @@ TypeCreate(Oid newTypeOid,
* relationKind and isImplicitArray are likewise somewhat expensive to deduce
* from the tuple, so we make callers pass those (they're not optional).
*
* isDependentType is true if this is an implicit array or relation rowtype;
* that means it doesn't need its own dependencies on owner etc.
* isDependentType is true if this is an implicit array, multirange, or
* relation rowtype; that means it doesn't need its own dependencies on owner
* etc.
*
* We make an extension-membership dependency if we're in an extension
* script and makeExtensionDep is true (and isDependentType isn't true).
@ -601,18 +603,23 @@ GenerateTypeDependencies(HeapTuple typeTuple,
* Make dependencies on namespace, owner, ACL, extension.
*
* Skip these for a dependent type, since it will have such dependencies
* indirectly through its depended-on type or relation.
* indirectly through its depended-on type or relation. An exception is
* that multiranges need their own namespace dependency, since we don't
* force them to be in the same schema as their range type.
*/
/* placeholder for all normal dependencies */
/* collects normal dependencies for bulk recording */
addrs_normal = new_object_addresses();
if (!isDependentType)
if (!isDependentType || typeForm->typtype == TYPTYPE_MULTIRANGE)
{
ObjectAddressSet(referenced, NamespaceRelationId,
typeForm->typnamespace);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
add_exact_object_address(&referenced, addrs_normal);
}
if (!isDependentType)
{
recordDependencyOnOwner(TypeRelationId, typeObjectId,
typeForm->typowner);
@ -727,6 +734,16 @@ GenerateTypeDependencies(HeapTuple typeTuple,
recordDependencyOn(&myself, &referenced,
isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
}
/*
* Note: you might expect that we should record an internal dependency of
* a multirange on its range type here, by analogy with the cases above.
* But instead, that is done by RangeCreate(), which also handles
* recording of other range-type-specific dependencies. That's pretty
* bogus. It's okay for now, because there are no cases where we need to
* regenerate the dependencies of a range or multirange type. But someday
* we might need to move that logic here to allow such regeneration.
*/
}
/*

View File

@ -777,6 +777,10 @@ GRANT EXECUTE ON FUNCTION pg_ls_logicalmapdir() TO pg_monitor;
GRANT EXECUTE ON FUNCTION pg_ls_replslotdir(text) TO pg_monitor;
GRANT EXECUTE ON FUNCTION pg_current_logfile() TO pg_monitor;
GRANT EXECUTE ON FUNCTION pg_current_logfile(text) TO pg_monitor;
GRANT pg_read_all_settings TO pg_monitor;
GRANT pg_read_all_stats TO pg_monitor;

View File

@ -3647,6 +3647,8 @@ RenameType(RenameStmt *stmt)
errhint("You can alter type %s, which will alter the array type as well.",
format_type_be(typTup->typelem))));
/* we do allow separate renaming of multirange types, though */
/*
* If type is composite we need to rename associated pg_class entry too.
* RenameRelationInternal will call RenameTypeInternal automatically.
@ -3730,6 +3732,21 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
errhint("You can alter type %s, which will alter the array type as well.",
format_type_be(typTup->typelem))));
/* don't allow direct alteration of multirange types, either */
if (typTup->typtype == TYPTYPE_MULTIRANGE)
{
Oid rangetype = get_multirange_range(typeOid);
/* We don't expect get_multirange_range to fail, but cope if so */
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot alter multirange type %s",
format_type_be(typeOid)),
OidIsValid(rangetype) ?
errhint("You can alter type %s, which will alter the multirange type as well.",
format_type_be(rangetype)) : 0));
}
/*
* If the new owner is the same as the existing owner, consider the
* command to have succeeded. This is for dump restoration purposes.
@ -3769,13 +3786,13 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
/*
* AlterTypeOwner_oid - change type owner unconditionally
*
* This function recurses to handle a pg_class entry, if necessary. It
* invokes any necessary access object hooks. If hasDependEntry is true, this
* function modifies the pg_shdepend entry appropriately (this should be
* passed as false only for table rowtypes and array types).
* This function recurses to handle dependent types (arrays and multiranges).
* It invokes any necessary access object hooks. If hasDependEntry is true,
* this function modifies the pg_shdepend entry appropriately (this should be
* passed as false only for table rowtypes and dependent types).
*
* This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
* OWNED BY. It assumes the caller has done all needed check.
* OWNED BY. It assumes the caller has done all needed checks.
*/
void
AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
@ -3815,7 +3832,7 @@ AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
* AlterTypeOwnerInternal - bare-bones type owner change.
*
* This routine simply modifies the owner of a pg_type entry, and recurses
* to handle a possible array type.
* to handle any dependent types.
*/
void
AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
@ -3865,6 +3882,19 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
if (OidIsValid(typTup->typarray))
AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
/* If it is a range type, update the associated multirange too */
if (typTup->typtype == TYPTYPE_RANGE)
{
Oid multirange_typeid = get_range_multirange(typeOid);
if (!OidIsValid(multirange_typeid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find multirange type for data type %s",
format_type_be(typeOid))));
AlterTypeOwnerInternal(multirange_typeid, newOwnerId);
}
/* Clean up */
table_close(rel, RowExclusiveLock);
}

View File

@ -1237,6 +1237,10 @@ create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel,
*
* Note that we must handle subpaths = NIL, representing a dummy access path.
* Also, there are callers that pass root = NULL.
*
* 'rows', when passed as a non-negative number, will be used to overwrite the
* returned path's row estimate. Otherwise, the row estimate is calculated
* by totalling the row estimates from the 'subpaths' list.
*/
AppendPath *
create_append_path(PlannerInfo *root,

View File

@ -1410,12 +1410,8 @@ AutoVacWorkerFailed(void)
static void
avl_sigusr2_handler(SIGNAL_ARGS)
{
int save_errno = errno;
got_SIGUSR2 = true;
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -852,15 +852,11 @@ IsCheckpointOnSchedule(double progress)
static void
ReqCheckpointHandler(SIGNAL_ARGS)
{
int save_errno = errno;
/*
* The signaling process should have set ckpt_flags nonzero, so all we
* need do is ensure that our main loop gets kicked out of any wait.
*/
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -60,12 +60,8 @@ HandleMainLoopInterrupts(void)
void
SignalHandlerForConfigReload(SIGNAL_ARGS)
{
int save_errno = errno;
ConfigReloadPending = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*
@ -108,10 +104,6 @@ SignalHandlerForCrashExit(SIGNAL_ARGS)
void
SignalHandlerForShutdownRequest(SIGNAL_ARGS)
{
int save_errno = errno;
ShutdownRequestPending = true;
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -283,13 +283,9 @@ PgArchWakeup(void)
static void
pgarch_waken_stop(SIGNAL_ARGS)
{
int save_errno = errno;
/* set flag to do a final cycle and shut down afterwards */
ready_to_stop = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*

View File

@ -2612,12 +2612,8 @@ InitProcessGlobals(void)
static void
handle_pm_pmsignal_signal(SIGNAL_ARGS)
{
int save_errno = errno;
pending_pm_pmsignal = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*
@ -2626,12 +2622,8 @@ handle_pm_pmsignal_signal(SIGNAL_ARGS)
static void
handle_pm_reload_request_signal(SIGNAL_ARGS)
{
int save_errno = errno;
pending_pm_reload_request = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*
@ -2711,8 +2703,6 @@ process_pm_reload_request(void)
static void
handle_pm_shutdown_request_signal(SIGNAL_ARGS)
{
int save_errno = errno;
switch (postgres_signal_arg)
{
case SIGTERM:
@ -2729,8 +2719,6 @@ handle_pm_shutdown_request_signal(SIGNAL_ARGS)
break;
}
SetLatch(MyLatch);
errno = save_errno;
}
/*
@ -2890,12 +2878,8 @@ process_pm_shutdown_request(void)
static void
handle_pm_child_exit_signal(SIGNAL_ARGS)
{
int save_errno = errno;
pending_pm_child_exit = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*

View File

@ -19,8 +19,6 @@
*/
#include "postgres.h"
#include <unistd.h>
#include "access/xlog.h"
#include "access/xlogrecovery.h"
#include "access/xlogutils.h"
@ -95,52 +93,27 @@ static void StartupProcExit(int code, Datum arg);
static void
StartupProcTriggerHandler(SIGNAL_ARGS)
{
int save_errno = errno;
promote_signaled = true;
WakeupRecovery();
errno = save_errno;
}
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
StartupProcSigHupHandler(SIGNAL_ARGS)
{
int save_errno = errno;
got_SIGHUP = true;
WakeupRecovery();
errno = save_errno;
}
/* SIGTERM: set flag to abort redo and exit */
static void
StartupProcShutdownHandler(SIGNAL_ARGS)
{
int save_errno = errno;
if (in_restore_command)
{
/*
* If we are in a child process (e.g., forked by system() in
* RestoreArchivedFile()), we don't want to call any exit callbacks.
* The parent will take care of that.
*/
if (MyProcPid == (int) getpid())
proc_exit(1);
else
{
write_stderr_signal_safe("StartupProcShutdownHandler() called in child process\n");
_exit(1);
}
}
proc_exit(1);
else
shutdown_requested = true;
WakeupRecovery();
errno = save_errno;
}
/*

View File

@ -1642,10 +1642,6 @@ RemoveLogrotateSignalFiles(void)
static void
sigUsr1Handler(SIGNAL_ARGS)
{
int save_errno = errno;
rotation_requested = true;
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -3476,12 +3476,8 @@ HandleWalSndInitStopping(void)
static void
WalSndLastCycleHandler(SIGNAL_ARGS)
{
int save_errno = errno;
got_SIGUSR2 = true;
SetLatch(MyLatch);
errno = save_errno;
}
/* Set up signal handlers */

View File

@ -2243,12 +2243,8 @@ GetNumRegisteredWaitEvents(WaitEventSet *set)
static void
latch_sigurg_handler(SIGNAL_ARGS)
{
int save_errno = errno;
if (waiting)
sendSelfPipeByte();
errno = save_errno;
}
/* Send one byte to the self-pipe, to wake up WaitLatch */

View File

@ -638,8 +638,6 @@ CheckProcSignal(ProcSignalReason reason)
void
procsignal_sigusr1_handler(SIGNAL_ARGS)
{
int save_errno = errno;
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
HandleCatchupInterrupt();
@ -683,6 +681,4 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -2970,8 +2970,6 @@ quickdie(SIGNAL_ARGS)
void
die(SIGNAL_ARGS)
{
int save_errno = errno;
/* Don't joggle the elbow of proc_exit */
if (!proc_exit_inprogress)
{
@ -2993,8 +2991,6 @@ die(SIGNAL_ARGS)
*/
if (DoingCommandRead && whereToSendOutput != DestRemote)
ProcessInterrupts();
errno = save_errno;
}
/*
@ -3004,8 +3000,6 @@ die(SIGNAL_ARGS)
void
StatementCancelHandler(SIGNAL_ARGS)
{
int save_errno = errno;
/*
* Don't joggle the elbow of proc_exit
*/
@ -3017,8 +3011,6 @@ StatementCancelHandler(SIGNAL_ARGS)
/* If we're still here, waken anything waiting on the process latch */
SetLatch(MyLatch);
errno = save_errno;
}
/* signal handler for floating point exception */

View File

@ -3737,31 +3737,3 @@ write_stderr(const char *fmt,...)
#endif
va_end(ap);
}
/*
* Write a message to STDERR using only async-signal-safe functions. This can
* be used to safely emit a message from a signal handler.
*
* TODO: It is likely possible to safely do a limited amount of string
* interpolation (e.g., %s and %d), but that is not presently supported.
*/
void
write_stderr_signal_safe(const char *str)
{
int nwritten = 0;
int ntotal = strlen(str);
while (nwritten < ntotal)
{
int rc;
rc = write(STDERR_FILENO, str + nwritten, ntotal - nwritten);
/* Just give up on error. There isn't much else we can do. */
if (rc == -1)
return;
nwritten += rc;
}
}

View File

@ -363,8 +363,6 @@ schedule_alarm(TimestampTz now)
static void
handle_sig_alarm(SIGNAL_ARGS)
{
int save_errno = errno;
/*
* Bump the holdoff counter, to make sure nothing we call will process
* interrupts directly. No timeout handler should do that, but these
@ -452,8 +450,6 @@ handle_sig_alarm(SIGNAL_ARGS)
}
RESUME_INTERRUPTS();
errno = save_errno;
}

View File

@ -1868,7 +1868,7 @@ selectDumpableType(TypeInfo *tyinfo, Archive *fout)
return;
}
/* skip auto-generated array types */
/* skip auto-generated array and multirange types */
if (tyinfo->isArray || tyinfo->isMultirange)
{
tyinfo->dobj.objType = DO_DUMMY_TYPE;
@ -1876,8 +1876,8 @@ selectDumpableType(TypeInfo *tyinfo, Archive *fout)
/*
* Fall through to set the dump flag; we assume that the subsequent
* rules will do the same thing as they would for the array's base
* type. (We cannot reliably look up the base type here, since
* getTypes may not have processed it yet.)
* type or multirange's range type. (We cannot reliably look up the
* base type here, since getTypes may not have processed it yet.)
*/
}
@ -5770,7 +5770,7 @@ getTypes(Archive *fout, int *numTypes)
else
tyinfo[i].isArray = false;
if (tyinfo[i].typtype == 'm')
if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
tyinfo[i].isMultirange = true;
else
tyinfo[i].isMultirange = false;

View File

@ -152,7 +152,6 @@ ResetCancelConn(void)
static void
handle_sigint(SIGNAL_ARGS)
{
int save_errno = errno;
char errbuf[256];
CancelRequested = true;
@ -173,8 +172,6 @@ handle_sigint(SIGNAL_ARGS)
write_stderr(errbuf);
}
}
errno = save_errno; /* just in case the write changed it */
}
/*

View File

@ -57,6 +57,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202402141
#define CATALOG_VERSION_NO 202402142
#endif

View File

@ -536,10 +536,4 @@ extern void write_jsonlog(ErrorData *edata);
*/
extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2);
/*
* Write a message to STDERR using only async-signal-safe functions. This can
* be used to safely emit a message from a signal handler.
*/
extern void write_stderr_signal_safe(const char *fmt);
#endif /* ELOG_H */

View File

@ -46,23 +46,105 @@
#include "c.h"
#include <signal.h>
#ifndef FRONTEND
#include <unistd.h>
#endif
#ifndef FRONTEND
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#endif
#ifdef PG_SIGNAL_COUNT /* Windows */
#define PG_NSIG (PG_SIGNAL_COUNT)
#elif defined(NSIG)
#define PG_NSIG (NSIG)
#else
#define PG_NSIG (64) /* XXX: wild guess */
#endif
/* Check a couple of common signals to make sure PG_NSIG is accurate. */
StaticAssertDecl(SIGUSR2 < PG_NSIG, "SIGUSR2 >= PG_NSIG");
StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG");
StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG");
StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG");
static volatile pqsigfunc pqsignal_handlers[PG_NSIG];
/*
* Except when called with SIG_IGN or SIG_DFL, pqsignal() sets up this function
* as the handler for all signals. This wrapper handler function checks that
* it is called within a process that the server knows about (i.e., any process
* that has called InitProcessGlobals(), such as a client backend), and not a
* child process forked by system(3), etc. This check ensures that such child
* processes do not modify shared memory, which is often detrimental. If the
* check succeeds, the function originally provided to pqsignal() is called.
* Otherwise, the default signal handler is installed and then called.
*
* This wrapper also handles restoring the value of errno.
*/
static void
wrapper_handler(SIGNAL_ARGS)
{
int save_errno = errno;
#ifndef FRONTEND
/*
* We expect processes to set MyProcPid before calling pqsignal() or
* before accepting signals.
*/
Assert(MyProcPid);
Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
if (unlikely(MyProcPid != (int) getpid()))
{
pqsignal(postgres_signal_arg, SIG_DFL);
raise(postgres_signal_arg);
return;
}
#endif
(*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
errno = save_errno;
}
/*
* Set up a signal handler, with SA_RESTART, for signal "signo"
*
* Returns the previous handler.
*
* NB: If called within a signal handler, race conditions may lead to bogus
* return values. You should either avoid calling this within signal handlers
* or ignore the return value.
*
* XXX: Since no in-tree callers use the return value, and there is little
* reason to do so, it would be nice if we could convert this to a void
* function instead of providing potentially-bogus return values.
* Unfortunately, that requires modifying the pqsignal() in legacy-pqsignal.c,
* which in turn requires an SONAME bump, which is probably not worth it.
*/
pqsigfunc
pqsignal(int signo, pqsigfunc func)
{
pqsigfunc orig_func = pqsignal_handlers[signo]; /* assumed atomic */
#if !(defined(WIN32) && defined(FRONTEND))
struct sigaction act,
oact;
#else
pqsigfunc ret;
#endif
Assert(signo < PG_NSIG);
if (func != SIG_IGN && func != SIG_DFL)
{
pqsignal_handlers[signo] = func; /* assumed atomic */
func = wrapper_handler;
}
#if !(defined(WIN32) && defined(FRONTEND))
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
@ -72,9 +154,15 @@ pqsignal(int signo, pqsigfunc func)
#endif
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
else if (oact.sa_handler == wrapper_handler)
return orig_func;
else
return oact.sa_handler;
#else
/* Forward to Windows native signal system. */
return signal(signo, func);
if ((ret = signal(signo, func)) == wrapper_handler)
return orig_func;
else
return ret;
#endif
}

View File

@ -171,7 +171,7 @@ $standby1->safe_psql('postgres', "SELECT pg_sync_replication_slots();");
# flagged as 'synced'
is( $standby1->safe_psql(
'postgres',
q{SELECT count(*) = 2 FROM pg_replication_slots WHERE slot_name IN ('lsub1_slot', 'lsub2_slot') AND synced;}
q{SELECT count(*) = 2 FROM pg_replication_slots WHERE slot_name IN ('lsub1_slot', 'lsub2_slot') AND synced AND NOT temporary;}
),
"t",
'logical slots have synced as true on standby');
@ -227,6 +227,13 @@ $standby1->reload;
$subscriber1->safe_psql('postgres',
"ALTER SUBSCRIPTION regress_mysub1 ENABLE");
# This wait ensures that confirmed_flush_lsn has been moved to latest
# position.
$primary->wait_for_catchup('regress_mysub1');
# To ensure that restart_lsn has moved to a recent WAL position, we need
# to log XLOG_RUNNING_XACTS and make sure the same is processed as well
$primary->psql('postgres', "CHECKPOINT");
$primary->wait_for_catchup('regress_mysub1');
# Do not allow any further advancement of the restart_lsn for the lsub1_slot.
@ -256,7 +263,7 @@ $standby1->wait_for_log(qr/dropped replication slot "lsub1_slot" of dbid [0-9]+/
# flagged as 'synced'
is( $standby1->safe_psql(
'postgres',
q{SELECT conflict_reason IS NULL AND synced FROM pg_replication_slots WHERE slot_name = 'lsub1_slot';}
q{SELECT conflict_reason IS NULL AND synced AND NOT temporary FROM pg_replication_slots WHERE slot_name = 'lsub1_slot';}
),
"t",
'logical slot is re-synced');

View File

@ -144,7 +144,6 @@ owner of sequence deptest_a_seq
owner of table deptest
owner of function deptest_func()
owner of type deptest_enum
owner of type deptest_multirange
owner of type deptest_range
owner of table deptest2
owner of sequence ss1

View File

@ -683,3 +683,23 @@ SELECT gist_stratnum_identity(18::smallint);
18
(1 row)
-- pg_current_logfile
CREATE ROLE regress_current_logfile;
-- not available by default
SELECT has_function_privilege('regress_current_logfile',
'pg_current_logfile()', 'EXECUTE');
has_function_privilege
------------------------
f
(1 row)
GRANT pg_monitor TO regress_current_logfile;
-- role has privileges of pg_monitor and can execute the function
SELECT has_function_privilege('regress_current_logfile',
'pg_current_logfile()', 'EXECUTE');
has_function_privilege
------------------------
t
(1 row)
DROP ROLE regress_current_logfile;

View File

@ -3115,6 +3115,36 @@ select _textrange1(textrange2('a','z')) @> 'b'::text;
drop type textrange1;
drop type textrange2;
--
-- Multiranges don't have their own ownership or permissions.
--
create type textrange1 as range(subtype=text, multirange_type_name=multitextrange1, collation="C");
create role regress_multirange_owner;
alter type multitextrange1 owner to regress_multirange_owner; -- fail
ERROR: cannot alter multirange type multitextrange1
HINT: You can alter type textrange1, which will alter the multirange type as well.
alter type textrange1 owner to regress_multirange_owner;
set role regress_multirange_owner;
revoke usage on type multitextrange1 from public; -- fail
ERROR: cannot set privileges of multirange types
HINT: Set the privileges of the range type instead.
revoke usage on type textrange1 from public;
\dT+ *textrange1*
List of data types
Schema | Name | Internal name | Size | Elements | Owner | Access privileges | Description
--------+-----------------+-----------------+------+----------+--------------------------+-----------------------------------------------------+-------------
public | multitextrange1 | multitextrange1 | var | | regress_multirange_owner | |
public | textrange1 | textrange1 | var | | regress_multirange_owner | regress_multirange_owner=U/regress_multirange_owner |
(2 rows)
create temp table test1(f1 multitextrange1[]);
revoke usage on type textrange1 from regress_multirange_owner;
create temp table test2(f1 multitextrange1[]); -- fail
ERROR: permission denied for type multitextrange1
drop table test1;
drop type textrange1;
reset role;
drop role regress_multirange_owner;
--
-- Test polymorphic type system
--
create function anyarray_anymultirange_func(a anyarray, r anymultirange)

View File

@ -254,3 +254,14 @@ FROM pg_walfile_name_offset('0/0'::pg_lsn + :segment_size - 1),
-- test stratnum support functions
SELECT gist_stratnum_identity(3::smallint);
SELECT gist_stratnum_identity(18::smallint);
-- pg_current_logfile
CREATE ROLE regress_current_logfile;
-- not available by default
SELECT has_function_privilege('regress_current_logfile',
'pg_current_logfile()', 'EXECUTE');
GRANT pg_monitor TO regress_current_logfile;
-- role has privileges of pg_monitor and can execute the function
SELECT has_function_privilege('regress_current_logfile',
'pg_current_logfile()', 'EXECUTE');
DROP ROLE regress_current_logfile;

View File

@ -700,6 +700,27 @@ select _textrange1(textrange2('a','z')) @> 'b'::text;
drop type textrange1;
drop type textrange2;
--
-- Multiranges don't have their own ownership or permissions.
--
create type textrange1 as range(subtype=text, multirange_type_name=multitextrange1, collation="C");
create role regress_multirange_owner;
alter type multitextrange1 owner to regress_multirange_owner; -- fail
alter type textrange1 owner to regress_multirange_owner;
set role regress_multirange_owner;
revoke usage on type multitextrange1 from public; -- fail
revoke usage on type textrange1 from public;
\dT+ *textrange1*
create temp table test1(f1 multitextrange1[]);
revoke usage on type textrange1 from regress_multirange_owner;
create temp table test2(f1 multitextrange1[]); -- fail
drop table test1;
drop type textrange1;
reset role;
drop role regress_multirange_owner;
--
-- Test polymorphic type system
--