diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c index a005e67..1023566 100644 *** a/src/backend/utils/adt/txid.c --- b/src/backend/utils/adt/txid.c *************** cmp_txid(const void *aa, const void *bb) *** 131,146 **** } /* ! * sort a snapshot's txids, so we can use bsearch() later. * * For consistency of on-disk representation, we always sort even if bsearch ! * will not be used. */ static void sort_snapshot(TxidSnapshot *snap) { if (snap->nxip > 1) qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid); } /* --- 131,161 ---- } /* ! * unique sort a snapshot's txids, so we can use bsearch() later. * * For consistency of on-disk representation, we always sort even if bsearch ! * will not be used. */ static void sort_snapshot(TxidSnapshot *snap) { + txid last = 0; + int nxip, idx1, idx2; + if (snap->nxip > 1) + { qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid); + nxip = snap->nxip; + idx1 = idx2 = 0; + while (idx1 < nxip) + { + if (snap->xip[idx1] != last) + last = snap->xip[idx2++] = snap->xip[idx1]; + else + snap->nxip--; + idx1++; + } + } } /* *************** parse_snapshot(const char *str) *** 294,304 **** val = str2txid(str, &endp); str = endp; ! /* require the input to be in order */ ! if (val < xmin || val >= xmax || val <= last_val) goto bad_format; ! buf_add_txid(buf, val); last_val = val; if (*str == ',') --- 309,320 ---- val = str2txid(str, &endp); str = endp; ! /* require the input to be in order and skip duplicates */ ! if (val < xmin || val >= xmax || val < last_val) goto bad_format; ! if (val != last_val) ! buf_add_txid(buf, val); last_val = val; if (*str == ',') *************** txid_current_snapshot(PG_FUNCTION_ARGS) *** 361,368 **** { TxidSnapshot *snap; uint32 nxip, ! i, ! size; TxidEpoch state; Snapshot cur; --- 377,383 ---- { TxidSnapshot *snap; uint32 nxip, ! i; TxidEpoch state; Snapshot cur; *************** txid_current_snapshot(PG_FUNCTION_ARGS) *** 381,389 **** /* allocate */ nxip = cur->xcnt; ! size = TXID_SNAPSHOT_SIZE(nxip); ! snap = palloc(size); ! SET_VARSIZE(snap, size); /* fill */ snap->xmin = convert_xid(cur->xmin, &state); --- 396,402 ---- /* allocate */ nxip = cur->xcnt; ! snap = palloc(TXID_SNAPSHOT_SIZE(nxip)); /* fill */ snap->xmin = convert_xid(cur->xmin, &state); *************** txid_current_snapshot(PG_FUNCTION_ARGS) *** 395,400 **** --- 408,416 ---- /* we want them guaranteed to be in ascending order */ sort_snapshot(snap); + /* we set the size here because the sort may have removed duplicate xips */ + SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(snap->nxip)); + PG_RETURN_POINTER(snap); } *************** txid_snapshot_recv(PG_FUNCTION_ARGS) *** 472,489 **** snap = palloc(TXID_SNAPSHOT_SIZE(nxip)); snap->xmin = xmin; snap->xmax = xmax; - snap->nxip = nxip; - SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip)); for (i = 0; i < nxip; i++) { txid cur = pq_getmsgint64(buf); ! if (cur <= last || cur < xmin || cur >= xmax) goto bad_format; snap->xip[i] = cur; last = cur; } PG_RETURN_POINTER(snap); bad_format: --- 488,514 ---- snap = palloc(TXID_SNAPSHOT_SIZE(nxip)); snap->xmin = xmin; snap->xmax = xmax; for (i = 0; i < nxip; i++) { txid cur = pq_getmsgint64(buf); ! if (cur < last || cur < xmin || cur >= xmax) goto bad_format; + + /* skip duplicate xips */ + if (cur == last) + { + i--; + nxip--; + continue; + } + snap->xip[i] = cur; last = cur; } + snap->nxip = nxip; + SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip)); PG_RETURN_POINTER(snap); bad_format: diff --git a/src/test/regress/expected/txid.out b/src/test/regress/expected/txid.out index 930b86a..7750b7b 100644 *** a/src/test/regress/expected/txid.out --- b/src/test/regress/expected/txid.out *************** select '12:18:14,16'::txid_snapshot; *** 12,17 **** --- 12,23 ---- 12:18:14,16 (1 row) + select '12:16:14,14'::txid_snapshot; + txid_snapshot + --------------- + 12:16:14 + (1 row) + -- errors select '31:12:'::txid_snapshot; ERROR: invalid input for txid_snapshot: "31:12:" *************** select '12:16:14,13'::txid_snapshot; *** 29,38 **** ERROR: invalid input for txid_snapshot: "12:16:14,13" LINE 1: select '12:16:14,13'::txid_snapshot; ^ - select '12:16:14,14'::txid_snapshot; - ERROR: invalid input for txid_snapshot: "12:16:14,14" - LINE 1: select '12:16:14,14'::txid_snapshot; - ^ create temp table snapshot_test ( nr integer, snap txid_snapshot --- 35,40 ---- diff --git a/src/test/regress/sql/txid.sql b/src/test/regress/sql/txid.sql index ecae10e..b6650b9 100644 *** a/src/test/regress/sql/txid.sql --- b/src/test/regress/sql/txid.sql *************** *** 3,15 **** -- i/o select '12:13:'::txid_snapshot; select '12:18:14,16'::txid_snapshot; -- errors select '31:12:'::txid_snapshot; select '0:1:'::txid_snapshot; select '12:13:0'::txid_snapshot; select '12:16:14,13'::txid_snapshot; - select '12:16:14,14'::txid_snapshot; create temp table snapshot_test ( nr integer, --- 3,15 ---- -- i/o select '12:13:'::txid_snapshot; select '12:18:14,16'::txid_snapshot; + select '12:16:14,14'::txid_snapshot; -- errors select '31:12:'::txid_snapshot; select '0:1:'::txid_snapshot; select '12:13:0'::txid_snapshot; select '12:16:14,13'::txid_snapshot; create temp table snapshot_test ( nr integer,