Skip to content

Commit af7611f

Browse files
authored
Merge branch 'apache:main' into main
2 parents ef77fd6 + 514da28 commit af7611f

18 files changed

Lines changed: 692 additions & 122 deletions

File tree

doc/src/sgml/func.sgml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15446,6 +15446,10 @@ table2-mapping
1544615446
<para>
1544715447
<literal>json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')</literal>
1544815448
<returnvalue>5</returnvalue>
15449+
</para>
15450+
<para>
15451+
<literal>jsonb_array_length('[]')</literal>
15452+
<returnvalue>0</returnvalue>
1544915453
</para></entry>
1545015454
</row>
1545115455

@@ -17887,10 +17891,19 @@ SELECT NULLIF(value, '(none)') ...
1788717891
</para>
1788817892
<para>
1788917893
Returns the length of the requested array dimension.
17894+
(Produces NULL instead of 0 for empty or missing array dimensions.)
1789017895
</para>
1789117896
<para>
1789217897
<literal>array_length(array[1,2,3], 1)</literal>
1789317898
<returnvalue>3</returnvalue>
17899+
</para>
17900+
<para>
17901+
<literal>array_length(array[]::int[], 1)</literal>
17902+
<returnvalue>NULL</returnvalue>
17903+
</para>
17904+
<para>
17905+
<literal>array_length(array['text'], 2)</literal>
17906+
<returnvalue>NULL</returnvalue>
1789417907
</para></entry>
1789517908
</row>
1789617909

doc/src/sgml/json.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -701,10 +701,10 @@ UPDATE table_name SET jsonb_field[2] = '2';
701701
assigned value can be placed.
702702

703703
<programlisting>
704-
-- Where jsonb_field was {}, it is now {'a': [{'b': 1}]}
704+
-- Where jsonb_field was {}, it is now {"a": [{"b": 1}]}
705705
UPDATE table_name SET jsonb_field['a'][0]['b'] = '1';
706706

707-
-- Where jsonb_field was [], it is now [null, {'a': 1}]
707+
-- Where jsonb_field was [], it is now [null, {"a": 1}]
708708
UPDATE table_name SET jsonb_field[1]['a'] = '1';
709709
</programlisting>
710710

src/backend/access/transam/transam.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,15 @@ TransactionIdDidAbortForReader(TransactionId transactionId)
249249
*
250250
* This does NOT look into pg_xact but merely probes our local cache
251251
* (and so it's not named TransactionIdDidComplete, which would be the
252-
* appropriate name for a function that worked that way). The intended
253-
* use is just to short-circuit TransactionIdIsInProgress calls when doing
254-
* repeated heapam_visibility.c checks for the same XID. If this isn't
255-
* extremely fast then it will be counterproductive.
252+
* appropriate name for a function that worked that way).
253+
*
254+
* NB: This is unused, and will be removed in v15. This was used to
255+
* short-circuit TransactionIdIsInProgress, but that was wrong for a
256+
* transaction that was known to be marked as committed in CLOG but not
257+
* yet removed from the proc array. This is kept in backbranches just in
258+
* case it is still used by extensions. However, extensions doing
259+
* something similar to tuple visibility checks should also be careful to
260+
* check the proc array first!
256261
*
257262
* Note:
258263
* Assumes transaction identifier is valid.

src/backend/storage/ipc/latch.c

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
#if defined(WAIT_USE_EPOLL) || defined(WAIT_USE_POLL) || \
7373
defined(WAIT_USE_KQUEUE) || defined(WAIT_USE_WIN32)
7474
/* don't overwrite manual choice */
75-
#elif defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_SIGNALFD_H)
75+
#elif defined(HAVE_SYS_EPOLL_H)
7676
#define WAIT_USE_EPOLL
7777
#elif defined(HAVE_KQUEUE)
7878
#define WAIT_USE_KQUEUE
@@ -84,6 +84,22 @@
8484
#error "no wait set implementation available"
8585
#endif
8686

87+
/*
88+
* By default, we use a self-pipe with poll() and a signalfd with epoll(), if
89+
* available. We avoid signalfd on illumos for now based on problem reports.
90+
* For testing the choice can also be manually specified.
91+
*/
92+
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_EPOLL)
93+
#if defined(WAIT_USE_SELF_PIPE) || defined(WAIT_USE_SIGNALFD)
94+
/* don't overwrite manual choice */
95+
#elif defined(WAIT_USE_EPOLL) && defined(HAVE_SYS_SIGNALFD_H) && \
96+
!defined(__illumos__)
97+
#define WAIT_USE_SIGNALFD
98+
#else
99+
#define WAIT_USE_SELF_PIPE
100+
#endif
101+
#endif
102+
87103
/* typedef in latch.h */
88104
struct WaitEventSet
89105
{
@@ -146,12 +162,12 @@ static WaitEventSet *LatchWaitSet;
146162
static volatile sig_atomic_t waiting = false;
147163
#endif
148164

149-
#ifdef WAIT_USE_EPOLL
165+
#ifdef WAIT_USE_SIGNALFD
150166
/* On Linux, we'll receive SIGURG via a signalfd file descriptor. */
151167
static int signal_fd = -1;
152168
#endif
153169

154-
#if defined(WAIT_USE_POLL)
170+
#ifdef WAIT_USE_SELF_PIPE
155171
/* Read and write ends of the self-pipe */
156172
static int selfpipe_readfd = -1;
157173
static int selfpipe_writefd = -1;
@@ -164,7 +180,7 @@ static void latch_sigurg_handler(SIGNAL_ARGS);
164180
static void sendSelfPipeByte(void);
165181
#endif
166182

167-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_EPOLL)
183+
#if defined(WAIT_USE_SELF_PIPE) || defined(WAIT_USE_SIGNALFD)
168184
static void drain(void);
169185
#endif
170186

@@ -190,7 +206,7 @@ static inline int WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
190206
void
191207
InitializeLatchSupport(void)
192208
{
193-
#if defined(WAIT_USE_POLL)
209+
#if defined(WAIT_USE_SELF_PIPE)
194210
int pipefd[2];
195211

196212
if (IsUnderPostmaster)
@@ -264,7 +280,7 @@ InitializeLatchSupport(void)
264280
pqsignal(SIGURG, latch_sigurg_handler);
265281
#endif
266282

267-
#ifdef WAIT_USE_EPOLL
283+
#ifdef WAIT_USE_SIGNALFD
268284
sigset_t signalfd_mask;
269285

270286
/* Block SIGURG, because we'll receive it through a signalfd. */
@@ -316,15 +332,15 @@ ShutdownLatchSupport(void)
316332
LatchWaitSet = NULL;
317333
}
318334

319-
#if defined(WAIT_USE_POLL)
335+
#if defined(WAIT_USE_SELF_PIPE)
320336
close(selfpipe_readfd);
321337
close(selfpipe_writefd);
322338
selfpipe_readfd = -1;
323339
selfpipe_writefd = -1;
324340
selfpipe_owner_pid = InvalidPid;
325341
#endif
326342

327-
#if defined(WAIT_USE_EPOLL)
343+
#if defined(WAIT_USE_SIGNALFD)
328344
close(signal_fd);
329345
signal_fd = -1;
330346
#endif
@@ -341,9 +357,12 @@ InitLatch(Latch *latch)
341357
latch->owner_pid = MyProcPid;
342358
latch->is_shared = false;
343359

344-
#if defined(WAIT_USE_POLL)
360+
#if defined(WAIT_USE_SELF_PIPE)
345361
/* Assert InitializeLatchSupport has been called in this process */
346362
Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
363+
#elif defined(WAIT_USE_SIGNALFD)
364+
/* Assert InitializeLatchSupport has been called in this process */
365+
Assert(signal_fd >= 0);
347366
#elif defined(WAIT_USE_WIN32)
348367
latch->event = CreateEvent(NULL, TRUE, FALSE, NULL);
349368
if (latch->event == NULL)
@@ -405,9 +424,12 @@ OwnLatch(Latch *latch)
405424
/* Sanity checks */
406425
Assert(latch->is_shared);
407426

408-
#if defined(WAIT_USE_POLL)
427+
#if defined(WAIT_USE_SELF_PIPE)
409428
/* Assert InitializeLatchSupport has been called in this process */
410429
Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
430+
#elif defined(WAIT_USE_SIGNALFD)
431+
/* Assert InitializeLatchSupport has been called in this process */
432+
Assert(signal_fd >= 0);
411433
#endif
412434

413435
if (latch->owner_pid != 0)
@@ -618,7 +640,7 @@ SetLatch(Latch *latch)
618640
return;
619641
else if (owner_pid == MyProcPid)
620642
{
621-
#if defined(WAIT_USE_POLL)
643+
#if defined(WAIT_USE_SELF_PIPE)
622644
if (waiting)
623645
sendSelfPipeByte();
624646
#else
@@ -983,9 +1005,9 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
9831005
{
9841006
set->latch = latch;
9851007
set->latch_pos = event->pos;
986-
#if defined(WAIT_USE_POLL)
1008+
#if defined(WAIT_USE_SELF_PIPE)
9871009
event->fd = selfpipe_readfd;
988-
#elif defined(WAIT_USE_EPOLL)
1010+
#elif defined(WAIT_USE_SIGNALFD)
9891011
event->fd = signal_fd;
9901012
#else
9911013
event->fd = PGINVALID_SOCKET;
@@ -2102,7 +2124,7 @@ GetNumRegisteredWaitEvents(WaitEventSet *set)
21022124
return set->nevents;
21032125
}
21042126

2105-
#if defined(WAIT_USE_POLL)
2127+
#if defined(WAIT_USE_SELF_PIPE)
21062128

21072129
/*
21082130
* SetLatch uses SIGURG to wake up the process waiting on the latch.
@@ -2153,7 +2175,7 @@ sendSelfPipeByte(void)
21532175

21542176
#endif
21552177

2156-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_EPOLL)
2178+
#if defined(WAIT_USE_SELF_PIPE) || defined(WAIT_USE_SIGNALFD)
21572179

21582180
/*
21592181
* Read all available data from self-pipe or signalfd.
@@ -2169,7 +2191,7 @@ drain(void)
21692191
int rc;
21702192
int fd;
21712193

2172-
#ifdef WAIT_USE_POLL
2194+
#ifdef WAIT_USE_SELF_PIPE
21732195
fd = selfpipe_readfd;
21742196
#else
21752197
fd = signal_fd;
@@ -2187,7 +2209,7 @@ drain(void)
21872209
else
21882210
{
21892211
waiting = false;
2190-
#ifdef WAIT_USE_POLL
2212+
#ifdef WAIT_USE_SELF_PIPE
21912213
elog(ERROR, "read() on self-pipe failed: %m");
21922214
#else
21932215
elog(ERROR, "read() on signalfd failed: %m");
@@ -2197,7 +2219,7 @@ drain(void)
21972219
else if (rc == 0)
21982220
{
21992221
waiting = false;
2200-
#ifdef WAIT_USE_POLL
2222+
#ifdef WAIT_USE_SELF_PIPE
22012223
elog(ERROR, "unexpected EOF on self-pipe");
22022224
#else
22032225
elog(ERROR, "unexpected EOF on signalfd");

src/backend/storage/ipc/procarray.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ static ProcArrayStruct *procArray;
277277
static PGPROC *allProcs;
278278
static TMGXACT *allTmGxact;
279279

280+
/*
281+
* Cache to reduce overhead of repeated calls to TransactionIdIsInProgress()
282+
*/
283+
static TransactionId cachedXidIsNotInProgress = InvalidTransactionId;
284+
280285
/*
281286
* Bookkeeping for tracking emulated transactions in recovery
282287
*/
@@ -1486,7 +1491,7 @@ TransactionIdIsInProgress(TransactionId xid)
14861491
* already known to be completed, we can fall out without any access to
14871492
* shared memory.
14881493
*/
1489-
if (TransactionIdIsKnownCompleted(xid))
1494+
if (TransactionIdEquals(cachedXidIsNotInProgress, xid))
14901495
{
14911496
xc_by_known_xact_inc();
14921497
return false;
@@ -1644,6 +1649,7 @@ TransactionIdIsInProgress(TransactionId xid)
16441649
if (nxids == 0)
16451650
{
16461651
xc_no_overflow_inc();
1652+
cachedXidIsNotInProgress = xid;
16471653
return false;
16481654
}
16491655

@@ -1658,7 +1664,10 @@ TransactionIdIsInProgress(TransactionId xid)
16581664
xc_slow_answer_inc();
16591665

16601666
if (TransactionIdDidAbort(xid))
1667+
{
1668+
cachedXidIsNotInProgress = xid;
16611669
return false;
1670+
}
16621671

16631672
/*
16641673
* It isn't aborted, so check whether the transaction tree it belongs to
@@ -1676,6 +1685,7 @@ TransactionIdIsInProgress(TransactionId xid)
16761685
}
16771686
}
16781687

1688+
cachedXidIsNotInProgress = xid;
16791689
return false;
16801690
}
16811691

src/backend/storage/ipc/signalfuncs.c

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ static int
5252
pg_signal_backend(int pid, int sig, char *msg)
5353
{
5454
PGPROC *proc = BackendPidGetProc(pid);
55-
LocalPgBackendStatus *local_beentry;
5655

5756
/*
5857
* BackendPidGetProc returns NULL if the pid isn't valid; but by the time
@@ -73,34 +72,14 @@ pg_signal_backend(int pid, int sig, char *msg)
7372
return SIGNAL_BACKEND_ERROR;
7473
}
7574

76-
local_beentry = pgstat_fetch_stat_local_beentry_by_pid(pid);
77-
78-
/* Only allow superusers to signal superuser-owned backends. */
79-
if (superuser_arg(proc->roleId) && !superuser())
80-
{
81-
Oid role;
82-
char * appname;
83-
84-
if (local_beentry == NULL) {
85-
return SIGNAL_BACKEND_NOSUPERUSER;
86-
}
87-
88-
role = get_role_oid("mdb_admin", true /*if nodoby created mdb_admin role in this database*/);
89-
appname = local_beentry->backendStatus.st_appname;
90-
91-
// only allow mdb_admin to kill su queries
92-
if (!is_member_of_role(GetUserId(), role)) {
93-
return SIGNAL_BACKEND_NOSUPERUSER;
94-
}
95-
96-
if (local_beentry->backendStatus.st_backendType == B_AUTOVAC_WORKER) {
97-
// ok
98-
} else if (appname != NULL && strcmp(appname, "MDB") == 0) {
99-
// ok
100-
} else {
101-
return SIGNAL_BACKEND_NOSUPERUSER;
102-
}
103-
}
75+
/*
76+
* Only allow superusers to signal superuser-owned backends. Any process
77+
* not advertising a role might have the importance of a superuser-owned
78+
* backend, so treat it that way.
79+
*/
80+
if ((!OidIsValid(proc->roleId) || superuser_arg(proc->roleId)) &&
81+
!superuser())
82+
return SIGNAL_BACKEND_NOSUPERUSER;
10483

10584
/* Users can signal backends they have role membership in. */
10685
if (!has_privs_of_role(GetUserId(), proc->roleId) &&

src/backend/utils/adt/xid8funcs.c

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "miscadmin.h"
3737
#include "postmaster/postmaster.h"
3838
#include "storage/lwlock.h"
39+
#include "storage/procarray.h"
3940
#include "utils/builtins.h"
4041
#include "utils/memutils.h"
4142
#include "utils/snapmgr.h"
@@ -810,29 +811,22 @@ pg_xact_status(PG_FUNCTION_ARGS)
810811
{
811812
Assert(TransactionIdIsValid(xid));
812813

813-
if (TransactionIdIsCurrentTransactionId(xid))
814+
/*
815+
* Like when doing visiblity checks on a row, check whether the
816+
* transaction is still in progress before looking into the CLOG.
817+
* Otherwise we would incorrectly return "committed" for a transaction
818+
* that is committing and has already updated the CLOG, but hasn't
819+
* removed its XID from the proc array yet. (See comment on that race
820+
* condition at the top of heapam_visibility.c)
821+
*/
822+
if (TransactionIdIsInProgress(xid))
814823
status = "in progress";
815824
else if (TransactionIdDidCommit(xid))
816825
status = "committed";
817-
else if (TransactionIdDidAbort(xid))
818-
status = "aborted";
819826
else
820827
{
821-
/*
822-
* The xact is not marked as either committed or aborted in clog.
823-
*
824-
* It could be a transaction that ended without updating clog or
825-
* writing an abort record due to a crash. We can safely assume
826-
* it's aborted if it isn't committed and is older than our
827-
* snapshot xmin.
828-
*
829-
* Otherwise it must be in-progress (or have been at the time we
830-
* checked commit/abort status).
831-
*/
832-
if (TransactionIdPrecedes(xid, GetActiveSnapshot()->xmin))
833-
status = "aborted";
834-
else
835-
status = "in progress";
828+
/* it must have aborted or crashed */
829+
status = "aborted";
836830
}
837831
}
838832
else

0 commit comments

Comments
 (0)