mirror of
https://github.com/postgres/postgres.git
synced 2025-08-10 00:03:33 -04:00
Compare commits
8 Commits
ddd5f4f54a
...
87027cb55b
Author | SHA1 | Date | |
---|---|---|---|
|
87027cb55b | ||
|
8fd0498de2 | ||
|
28e4632509 | ||
|
3b00fdba9f | ||
|
8d8afd48d3 | ||
|
3e8235ba4f | ||
|
bd8fc1677b | ||
|
b8f9e77725 |
@ -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>
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1642,10 +1642,6 @@ RemoveLogrotateSignalFiles(void)
|
||||
static void
|
||||
sigUsr1Handler(SIGNAL_ARGS)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
rotation_requested = true;
|
||||
SetLatch(MyLatch);
|
||||
|
||||
errno = save_errno;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -57,6 +57,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202402141
|
||||
#define CATALOG_VERSION_NO 202402142
|
||||
|
||||
#endif
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
--
|
||||
|
Loading…
x
Reference in New Issue
Block a user