mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Remove contrib/txid, in preparation for migrating it into core.
This commit is contained in:
parent
041a8b37f5
commit
17333b6d09
@ -1,4 +1,4 @@
|
|||||||
# $PostgreSQL: pgsql/contrib/Makefile,v 1.79 2007/10/07 23:32:19 wieck Exp $
|
# $PostgreSQL: pgsql/contrib/Makefile,v 1.80 2007/10/13 22:59:43 tgl Exp $
|
||||||
|
|
||||||
subdir = contrib
|
subdir = contrib
|
||||||
top_builddir = ..
|
top_builddir = ..
|
||||||
@ -30,7 +30,6 @@ WANTED_DIRS = \
|
|||||||
pgstattuple \
|
pgstattuple \
|
||||||
seg \
|
seg \
|
||||||
spi \
|
spi \
|
||||||
txid \
|
|
||||||
tablefunc \
|
tablefunc \
|
||||||
vacuumlo
|
vacuumlo
|
||||||
|
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
# $PostgreSQL: pgsql/contrib/txid/Makefile,v 1.2 2007/10/11 19:54:17 tgl Exp $
|
|
||||||
|
|
||||||
MODULES = txid
|
|
||||||
DATA_built = txid.sql
|
|
||||||
DATA = uninstall_txid.sql
|
|
||||||
DOCS = README.txid
|
|
||||||
REGRESS = txid
|
|
||||||
|
|
||||||
ifdef USE_PGXS
|
|
||||||
PG_CONFIG = pg_config
|
|
||||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
|
||||||
include $(PGXS)
|
|
||||||
else
|
|
||||||
subdir = contrib/txid
|
|
||||||
top_builddir = ../..
|
|
||||||
include $(top_builddir)/src/Makefile.global
|
|
||||||
include $(top_srcdir)/contrib/contrib-global.mk
|
|
||||||
endif
|
|
@ -1,106 +0,0 @@
|
|||||||
txid - export transaction IDs to user level
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
The goal is to make PostgreSQL's internal transaction ID and snapshot
|
|
||||||
data usable externally. This allows very efficient queue
|
|
||||||
implementation done inside database.
|
|
||||||
|
|
||||||
[towrite: what snapshot means]
|
|
||||||
|
|
||||||
The module defines type txid_snapshot and following functions:
|
|
||||||
|
|
||||||
|
|
||||||
txid_current() returns int8
|
|
||||||
|
|
||||||
Current transaction ID.
|
|
||||||
|
|
||||||
txid_current_snapshot() returns txid_snapshot
|
|
||||||
|
|
||||||
Current snapshot.
|
|
||||||
|
|
||||||
txid_snapshot_xmin( snap ) returns int8
|
|
||||||
|
|
||||||
Smallest TXID in snapshot. TXID's smaller than this
|
|
||||||
are all visible in snapshot.
|
|
||||||
|
|
||||||
txid_snapshot_xmax( snap ) returns int8
|
|
||||||
|
|
||||||
Largest TXID in snapshot. TXID's starting from this one are
|
|
||||||
all invisible in snapshot.
|
|
||||||
|
|
||||||
txid_snapshot_xip( snap ) setof int8
|
|
||||||
|
|
||||||
List of in-progress TXID's in snapshot, that are invisible.
|
|
||||||
Values are between xmin (inclusive) and xmax (exclusive).
|
|
||||||
|
|
||||||
txid_visible_in_snapshot(id, snap) returns bool
|
|
||||||
|
|
||||||
Is TXID visible in snapshot?
|
|
||||||
|
|
||||||
|
|
||||||
Fetching events
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Lets say there is following event table:
|
|
||||||
|
|
||||||
CREATE TABLE events (
|
|
||||||
ev_txid int8 not null default txid_current(),
|
|
||||||
ev_data text
|
|
||||||
);
|
|
||||||
CREATE INDEX ev_txid_idx ON events (ev_txid);
|
|
||||||
|
|
||||||
Then event between 2 snapshots snap1 and snap2 can be fetched
|
|
||||||
with followign query:
|
|
||||||
|
|
||||||
SELECT ev_data FROM events
|
|
||||||
WHERE ev_txid >= txid_snapshot_xmin(:snap1)
|
|
||||||
AND ev_txid < txid_snapshot_xmax(:snap2)
|
|
||||||
AND NOT txid_visible_in_snapshot(ev_txid, :snap1)
|
|
||||||
AND txid_visible_in_snapshot(ev_txid, :snap2);
|
|
||||||
|
|
||||||
This is the simplest query but it has problem if there are long
|
|
||||||
transactions running - the txid_snapshot_xmin(snap1) will stay low
|
|
||||||
and the range will get very large.
|
|
||||||
|
|
||||||
This can be fixed by fetching only snap1.xmax ... snap1.xmax by range and
|
|
||||||
fetching possible txids below snap1.xmax explicitly:
|
|
||||||
|
|
||||||
SELECT ev_data FROM events
|
|
||||||
WHERE ((ev_txid >= txid_snapshot_xmax(:snap1) AND ev_txid < txid_snapshot_xmax(:snap2))
|
|
||||||
OR
|
|
||||||
(ev_txid IN (SELECT * FROM txid_snapshot_xip(:snap1))))
|
|
||||||
AND NOT txid_visible_in_snapshot(ev_txid, :snap1)
|
|
||||||
AND txid_visible_in_snapshot(ev_txid, :snap2);
|
|
||||||
|
|
||||||
Note that although the above queries work, PostgreSQL fails to
|
|
||||||
plan them efficiently. For actual usage the values for txid_snapshot_xmin,
|
|
||||||
txid_snapshot_xmax and txid_snapshot_xip should be filled in directly,
|
|
||||||
only then will they use index.
|
|
||||||
|
|
||||||
There are few more optimizations possible, like:
|
|
||||||
|
|
||||||
- Picking out only TXIDs that were actually committed between snap1 and snap2.
|
|
||||||
|
|
||||||
- Lowering the range from txid_snapshot_xmax(snap1) to decrease the list if TXIDs to be fetched separately.
|
|
||||||
|
|
||||||
To see example code for that it's best to see pgq.batch_event_sql() function in Skytools.
|
|
||||||
|
|
||||||
http://pgfoundry.org/projects/skytools/
|
|
||||||
|
|
||||||
|
|
||||||
Dumping and restoring data containing TXIDs.
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
When reloading TXID data you will typically want to be sure that the current
|
|
||||||
XID counter is beyond the reloaded data. The easiest way to do this is to
|
|
||||||
increase the XID epoch to beyond the largest one in the input data.
|
|
||||||
|
|
||||||
You can look at current epoch with queries such as:
|
|
||||||
|
|
||||||
SELECT MAX(txid) >> 32 as epoch FROM ...;
|
|
||||||
|
|
||||||
Epoch can be changed with pg_resetxlog command:
|
|
||||||
|
|
||||||
pg_resetxlog -e NEWEPOCH DATADIR
|
|
||||||
|
|
||||||
Database needs to be shut down for that moment.
|
|
@ -1,221 +0,0 @@
|
|||||||
-- init
|
|
||||||
\set ECHO none
|
|
||||||
-- i/o
|
|
||||||
select '12:13:'::txid_snapshot;
|
|
||||||
txid_snapshot
|
|
||||||
---------------
|
|
||||||
12:13:
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select '12:13:1,2'::txid_snapshot;
|
|
||||||
ERROR: invalid input for txid_snapshot: "12:13:1,2"
|
|
||||||
-- errors
|
|
||||||
select '31:12:'::txid_snapshot;
|
|
||||||
ERROR: invalid input for txid_snapshot: "31:12:"
|
|
||||||
select '0:1:'::txid_snapshot;
|
|
||||||
ERROR: invalid input for txid_snapshot: "0:1:"
|
|
||||||
select '12:13:0'::txid_snapshot;
|
|
||||||
ERROR: invalid input for txid_snapshot: "12:13:0"
|
|
||||||
select '12:16:14,13'::txid_snapshot;
|
|
||||||
ERROR: invalid input for txid_snapshot: "12:16:14,13"
|
|
||||||
select '12:16:14,14'::txid_snapshot;
|
|
||||||
ERROR: invalid input for txid_snapshot: "12:16:14,14"
|
|
||||||
create table snapshot_test (
|
|
||||||
nr integer,
|
|
||||||
snap txid_snapshot
|
|
||||||
);
|
|
||||||
insert into snapshot_test values (1, '12:13:');
|
|
||||||
insert into snapshot_test values (2, '12:20:13,15,18');
|
|
||||||
insert into snapshot_test values (3, '100001:100009:100005,100007,100008');
|
|
||||||
insert into snapshot_test values (4, '100:150:101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131');
|
|
||||||
select snap from snapshot_test order by nr;
|
|
||||||
snap
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
12:13:
|
|
||||||
12:20:13,15,18
|
|
||||||
100001:100009:100005,100007,100008
|
|
||||||
100:150:101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131
|
|
||||||
(4 rows)
|
|
||||||
|
|
||||||
select txid_snapshot_xmin(snap),
|
|
||||||
txid_snapshot_xmax(snap),
|
|
||||||
txid_snapshot_xip(snap)
|
|
||||||
from snapshot_test order by nr;
|
|
||||||
txid_snapshot_xmin | txid_snapshot_xmax | txid_snapshot_xip
|
|
||||||
--------------------+--------------------+-------------------
|
|
||||||
12 | 20 | 13
|
|
||||||
12 | 20 | 15
|
|
||||||
12 | 20 | 18
|
|
||||||
100001 | 100009 | 100005
|
|
||||||
100001 | 100009 | 100007
|
|
||||||
100001 | 100009 | 100008
|
|
||||||
100 | 150 | 101
|
|
||||||
100 | 150 | 102
|
|
||||||
100 | 150 | 103
|
|
||||||
100 | 150 | 104
|
|
||||||
100 | 150 | 105
|
|
||||||
100 | 150 | 106
|
|
||||||
100 | 150 | 107
|
|
||||||
100 | 150 | 108
|
|
||||||
100 | 150 | 109
|
|
||||||
100 | 150 | 110
|
|
||||||
100 | 150 | 111
|
|
||||||
100 | 150 | 112
|
|
||||||
100 | 150 | 113
|
|
||||||
100 | 150 | 114
|
|
||||||
100 | 150 | 115
|
|
||||||
100 | 150 | 116
|
|
||||||
100 | 150 | 117
|
|
||||||
100 | 150 | 118
|
|
||||||
100 | 150 | 119
|
|
||||||
100 | 150 | 120
|
|
||||||
100 | 150 | 121
|
|
||||||
100 | 150 | 122
|
|
||||||
100 | 150 | 123
|
|
||||||
100 | 150 | 124
|
|
||||||
100 | 150 | 125
|
|
||||||
100 | 150 | 126
|
|
||||||
100 | 150 | 127
|
|
||||||
100 | 150 | 128
|
|
||||||
100 | 150 | 129
|
|
||||||
100 | 150 | 130
|
|
||||||
100 | 150 | 131
|
|
||||||
(37 rows)
|
|
||||||
|
|
||||||
select id, txid_visible_in_snapshot(id, snap)
|
|
||||||
from snapshot_test, generate_series(11, 21) id
|
|
||||||
where nr = 2;
|
|
||||||
id | txid_visible_in_snapshot
|
|
||||||
----+--------------------------
|
|
||||||
11 | t
|
|
||||||
12 | t
|
|
||||||
13 | f
|
|
||||||
14 | t
|
|
||||||
15 | f
|
|
||||||
16 | t
|
|
||||||
17 | t
|
|
||||||
18 | f
|
|
||||||
19 | t
|
|
||||||
20 | f
|
|
||||||
21 | f
|
|
||||||
(11 rows)
|
|
||||||
|
|
||||||
-- test bsearch
|
|
||||||
select id, txid_visible_in_snapshot(id, snap)
|
|
||||||
from snapshot_test, generate_series(90, 160) id
|
|
||||||
where nr = 4;
|
|
||||||
id | txid_visible_in_snapshot
|
|
||||||
-----+--------------------------
|
|
||||||
90 | t
|
|
||||||
91 | t
|
|
||||||
92 | t
|
|
||||||
93 | t
|
|
||||||
94 | t
|
|
||||||
95 | t
|
|
||||||
96 | t
|
|
||||||
97 | t
|
|
||||||
98 | t
|
|
||||||
99 | t
|
|
||||||
100 | t
|
|
||||||
101 | f
|
|
||||||
102 | f
|
|
||||||
103 | f
|
|
||||||
104 | f
|
|
||||||
105 | f
|
|
||||||
106 | f
|
|
||||||
107 | f
|
|
||||||
108 | f
|
|
||||||
109 | f
|
|
||||||
110 | f
|
|
||||||
111 | f
|
|
||||||
112 | f
|
|
||||||
113 | f
|
|
||||||
114 | f
|
|
||||||
115 | f
|
|
||||||
116 | f
|
|
||||||
117 | f
|
|
||||||
118 | f
|
|
||||||
119 | f
|
|
||||||
120 | f
|
|
||||||
121 | f
|
|
||||||
122 | f
|
|
||||||
123 | f
|
|
||||||
124 | f
|
|
||||||
125 | f
|
|
||||||
126 | f
|
|
||||||
127 | f
|
|
||||||
128 | f
|
|
||||||
129 | f
|
|
||||||
130 | f
|
|
||||||
131 | f
|
|
||||||
132 | t
|
|
||||||
133 | t
|
|
||||||
134 | t
|
|
||||||
135 | t
|
|
||||||
136 | t
|
|
||||||
137 | t
|
|
||||||
138 | t
|
|
||||||
139 | t
|
|
||||||
140 | t
|
|
||||||
141 | t
|
|
||||||
142 | t
|
|
||||||
143 | t
|
|
||||||
144 | t
|
|
||||||
145 | t
|
|
||||||
146 | t
|
|
||||||
147 | t
|
|
||||||
148 | t
|
|
||||||
149 | t
|
|
||||||
150 | f
|
|
||||||
151 | f
|
|
||||||
152 | f
|
|
||||||
153 | f
|
|
||||||
154 | f
|
|
||||||
155 | f
|
|
||||||
156 | f
|
|
||||||
157 | f
|
|
||||||
158 | f
|
|
||||||
159 | f
|
|
||||||
160 | f
|
|
||||||
(71 rows)
|
|
||||||
|
|
||||||
-- test current values also
|
|
||||||
select txid_current() >= txid_snapshot_xmin(txid_current_snapshot());
|
|
||||||
?column?
|
|
||||||
----------
|
|
||||||
t
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
/* due to lazy xid alloc in 8.3 those are different in 8.2 and 8.3
|
|
||||||
select txid_current() < txid_snapshot_xmax(txid_current_snapshot());
|
|
||||||
|
|
||||||
select txid_visible_in_snapshot(txid_current(), txid_current_snapshot());
|
|
||||||
*/
|
|
||||||
-- test 64bitness
|
|
||||||
select txid_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100010001013';
|
|
||||||
txid_snapshot
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
1000100010001000:1000100010001100:1000100010001012,1000100010001013
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select txid_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
|
|
||||||
txid_visible_in_snapshot
|
|
||||||
--------------------------
|
|
||||||
f
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
|
|
||||||
txid_visible_in_snapshot
|
|
||||||
--------------------------
|
|
||||||
t
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
-- test 64bit overflow
|
|
||||||
SELECT txid_snapshot '1:9223372036854775807:3';
|
|
||||||
txid_snapshot
|
|
||||||
-------------------------
|
|
||||||
1:9223372036854775807:3
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT txid_snapshot '1:9223372036854775808:3';
|
|
||||||
ERROR: invalid input for txid_snapshot: "1:9223372036854775808:3"
|
|
@ -1,61 +0,0 @@
|
|||||||
-- init
|
|
||||||
\set ECHO none
|
|
||||||
set client_min_messages = 'warning';
|
|
||||||
\i txid.sql
|
|
||||||
set client_min_messages = 'notice';
|
|
||||||
\set ECHO all
|
|
||||||
|
|
||||||
-- i/o
|
|
||||||
select '12:13:'::txid_snapshot;
|
|
||||||
select '12:13:1,2'::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 table snapshot_test (
|
|
||||||
nr integer,
|
|
||||||
snap txid_snapshot
|
|
||||||
);
|
|
||||||
|
|
||||||
insert into snapshot_test values (1, '12:13:');
|
|
||||||
insert into snapshot_test values (2, '12:20:13,15,18');
|
|
||||||
insert into snapshot_test values (3, '100001:100009:100005,100007,100008');
|
|
||||||
insert into snapshot_test values (4, '100:150:101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131');
|
|
||||||
select snap from snapshot_test order by nr;
|
|
||||||
|
|
||||||
select txid_snapshot_xmin(snap),
|
|
||||||
txid_snapshot_xmax(snap),
|
|
||||||
txid_snapshot_xip(snap)
|
|
||||||
from snapshot_test order by nr;
|
|
||||||
|
|
||||||
select id, txid_visible_in_snapshot(id, snap)
|
|
||||||
from snapshot_test, generate_series(11, 21) id
|
|
||||||
where nr = 2;
|
|
||||||
|
|
||||||
-- test bsearch
|
|
||||||
select id, txid_visible_in_snapshot(id, snap)
|
|
||||||
from snapshot_test, generate_series(90, 160) id
|
|
||||||
where nr = 4;
|
|
||||||
|
|
||||||
-- test current values also
|
|
||||||
select txid_current() >= txid_snapshot_xmin(txid_current_snapshot());
|
|
||||||
|
|
||||||
/* due to lazy xid alloc in 8.3 those are different in 8.2 and 8.3
|
|
||||||
select txid_current() < txid_snapshot_xmax(txid_current_snapshot());
|
|
||||||
|
|
||||||
select txid_visible_in_snapshot(txid_current(), txid_current_snapshot());
|
|
||||||
*/
|
|
||||||
|
|
||||||
-- test 64bitness
|
|
||||||
|
|
||||||
select txid_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100010001013';
|
|
||||||
select txid_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
|
|
||||||
select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
|
|
||||||
|
|
||||||
-- test 64bit overflow
|
|
||||||
SELECT txid_snapshot '1:9223372036854775807:3';
|
|
||||||
SELECT txid_snapshot '1:9223372036854775808:3';
|
|
@ -1,603 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
* txid.c
|
|
||||||
*
|
|
||||||
* Export internal transaction IDs to user level.
|
|
||||||
*
|
|
||||||
* Note that only top-level transaction IDs are ever converted to TXID.
|
|
||||||
* This is important because TXIDs frequently persist beyond the global
|
|
||||||
* xmin horizon, or may even be shipped to other machines, so we cannot
|
|
||||||
* rely on being able to correlate subtransaction IDs with their parents
|
|
||||||
* via functions such as SubTransGetTopmostTransaction().
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
|
||||||
* Author: Jan Wieck, Afilias USA INC.
|
|
||||||
* 64-bit txids: Marko Kreen, Skype Technologies
|
|
||||||
*
|
|
||||||
* $PostgreSQL: pgsql/contrib/txid/txid.c,v 1.4 2007/10/11 19:54:17 tgl Exp $
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
|
|
||||||
#include "access/transam.h"
|
|
||||||
#include "access/xact.h"
|
|
||||||
#include "funcapi.h"
|
|
||||||
#include "libpq/pqformat.h"
|
|
||||||
|
|
||||||
|
|
||||||
PG_MODULE_MAGIC;
|
|
||||||
|
|
||||||
#ifdef INT64_IS_BUSTED
|
|
||||||
#error txid needs working int64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* txid will be signed int8 in database, so must limit to 63 bits */
|
|
||||||
#define MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF)
|
|
||||||
|
|
||||||
/* Use unsigned variant internally */
|
|
||||||
typedef uint64 txid;
|
|
||||||
|
|
||||||
/* sprintf format code for uint64 */
|
|
||||||
#define TXID_FMT UINT64_FORMAT
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If defined, use bsearch() function for searching for txids in snapshots
|
|
||||||
* that have more than the specified number of values.
|
|
||||||
*/
|
|
||||||
#define USE_BSEARCH_IF_NXIP_GREATER 30
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Snapshot containing 8byte txids.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* 4-byte length hdr, should not be touched directly.
|
|
||||||
*
|
|
||||||
* Explicit embedding is ok as we want always correct
|
|
||||||
* alignment anyway.
|
|
||||||
*/
|
|
||||||
int32 __varsz;
|
|
||||||
|
|
||||||
uint32 nxip; /* number of txids in xip array */
|
|
||||||
txid xmin;
|
|
||||||
txid xmax;
|
|
||||||
txid xip[1]; /* in-progress txids, xmin <= xip[i] < xmax */
|
|
||||||
} TxidSnapshot;
|
|
||||||
|
|
||||||
#define TXID_SNAPSHOT_SIZE(nxip) \
|
|
||||||
(offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Epoch values from xact.c
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
TransactionId last_xid;
|
|
||||||
uint32 epoch;
|
|
||||||
} TxidEpoch;
|
|
||||||
|
|
||||||
|
|
||||||
/* public functions */
|
|
||||||
Datum txid_snapshot_in(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_snapshot_out(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_snapshot_recv(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_snapshot_send(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_current(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_current_snapshot(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_snapshot_xmin(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_snapshot_xmax(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_snapshot_xip(PG_FUNCTION_ARGS);
|
|
||||||
Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS);
|
|
||||||
|
|
||||||
/* public function tags */
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_in);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_out);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_recv);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_send);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_current);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_current_snapshot);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_xmin);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_xmax);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_xip);
|
|
||||||
PG_FUNCTION_INFO_V1(txid_visible_in_snapshot);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fetch epoch data from xact.c.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
load_xid_epoch(TxidEpoch *state)
|
|
||||||
{
|
|
||||||
GetNextXidAndEpoch(&state->last_xid, &state->epoch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* do a TransactionId -> txid conversion for an XID near the given epoch
|
|
||||||
*/
|
|
||||||
static txid
|
|
||||||
convert_xid(TransactionId xid, const TxidEpoch *state)
|
|
||||||
{
|
|
||||||
uint64 epoch;
|
|
||||||
|
|
||||||
/* return special xid's as-is */
|
|
||||||
if (!TransactionIdIsNormal(xid))
|
|
||||||
return (txid) xid;
|
|
||||||
|
|
||||||
/* xid can be on either side when near wrap-around */
|
|
||||||
epoch = (uint64) state->epoch;
|
|
||||||
if (xid > state->last_xid &&
|
|
||||||
TransactionIdPrecedes(xid, state->last_xid))
|
|
||||||
epoch--;
|
|
||||||
else if (xid < state->last_xid &&
|
|
||||||
TransactionIdFollows(xid, state->last_xid))
|
|
||||||
epoch++;
|
|
||||||
|
|
||||||
return (epoch << 32) | xid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid comparator for qsort/bsearch
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
cmp_txid(const void *aa, const void *bb)
|
|
||||||
{
|
|
||||||
txid a = *(const txid *) aa;
|
|
||||||
txid b = *(const txid *) bb;
|
|
||||||
|
|
||||||
if (a < b)
|
|
||||||
return -1;
|
|
||||||
if (a > b)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check txid visibility.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
is_visible_txid(txid value, const TxidSnapshot *snap)
|
|
||||||
{
|
|
||||||
if (value < snap->xmin)
|
|
||||||
return true;
|
|
||||||
else if (value >= snap->xmax)
|
|
||||||
return false;
|
|
||||||
#ifdef USE_BSEARCH_IF_NXIP_GREATER
|
|
||||||
else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
|
|
||||||
{
|
|
||||||
void *res;
|
|
||||||
|
|
||||||
res = bsearch(&value, snap->xip, snap->nxip, sizeof(txid), cmp_txid);
|
|
||||||
/* if found, transaction is still in progress */
|
|
||||||
return (res) ? false : true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32 i;
|
|
||||||
|
|
||||||
for (i = 0; i < snap->nxip; i++)
|
|
||||||
{
|
|
||||||
if (value == snap->xip[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* helper functions to use StringInfo for TxidSnapshot creation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static StringInfo
|
|
||||||
buf_init(txid xmin, txid xmax)
|
|
||||||
{
|
|
||||||
TxidSnapshot snap;
|
|
||||||
StringInfo buf;
|
|
||||||
|
|
||||||
snap.xmin = xmin;
|
|
||||||
snap.xmax = xmax;
|
|
||||||
snap.nxip = 0;
|
|
||||||
|
|
||||||
buf = makeStringInfo();
|
|
||||||
appendBinaryStringInfo(buf, (char *)&snap, TXID_SNAPSHOT_SIZE(0));
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
buf_add_txid(StringInfo buf, txid xid)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *)buf->data;
|
|
||||||
|
|
||||||
/* do this before possible realloc */
|
|
||||||
snap->nxip++;
|
|
||||||
|
|
||||||
appendBinaryStringInfo(buf, (char *)&xid, sizeof(xid));
|
|
||||||
}
|
|
||||||
|
|
||||||
static TxidSnapshot *
|
|
||||||
buf_finalize(StringInfo buf)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *)buf->data;
|
|
||||||
|
|
||||||
SET_VARSIZE(snap, buf->len);
|
|
||||||
|
|
||||||
/* buf is not needed anymore */
|
|
||||||
buf->data = NULL;
|
|
||||||
pfree(buf);
|
|
||||||
|
|
||||||
return snap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* simple number parser.
|
|
||||||
*
|
|
||||||
* We return 0 on error, which is invalid value for txid.
|
|
||||||
*/
|
|
||||||
static txid
|
|
||||||
str2txid(const char *s, const char **endp)
|
|
||||||
{
|
|
||||||
txid val = 0;
|
|
||||||
txid cutoff = MAX_TXID / 10;
|
|
||||||
txid cutlim = MAX_TXID % 10;
|
|
||||||
|
|
||||||
for (; *s; s++)
|
|
||||||
{
|
|
||||||
unsigned d;
|
|
||||||
|
|
||||||
if (*s < '0' || *s > '9')
|
|
||||||
break;
|
|
||||||
d = *s - '0';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check for overflow
|
|
||||||
*/
|
|
||||||
if (val > cutoff || (val == cutoff && d > cutlim))
|
|
||||||
{
|
|
||||||
val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
val = val * 10 + d;
|
|
||||||
}
|
|
||||||
if (endp)
|
|
||||||
*endp = s;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* parse snapshot from cstring
|
|
||||||
*/
|
|
||||||
static TxidSnapshot *
|
|
||||||
parse_snapshot(const char *str)
|
|
||||||
{
|
|
||||||
txid xmin;
|
|
||||||
txid xmax;
|
|
||||||
txid last_val = 0, val;
|
|
||||||
const char *str_start = str;
|
|
||||||
const char *endp;
|
|
||||||
StringInfo buf;
|
|
||||||
|
|
||||||
xmin = str2txid(str, &endp);
|
|
||||||
if (*endp != ':')
|
|
||||||
goto bad_format;
|
|
||||||
str = endp + 1;
|
|
||||||
|
|
||||||
xmax = str2txid(str, &endp);
|
|
||||||
if (*endp != ':')
|
|
||||||
goto bad_format;
|
|
||||||
str = endp + 1;
|
|
||||||
|
|
||||||
/* it should look sane */
|
|
||||||
if (xmin == 0 || xmax == 0 || xmin > xmax)
|
|
||||||
goto bad_format;
|
|
||||||
|
|
||||||
/* allocate buffer */
|
|
||||||
buf = buf_init(xmin, xmax);
|
|
||||||
|
|
||||||
/* loop over values */
|
|
||||||
while (*str != '\0')
|
|
||||||
{
|
|
||||||
/* read next value */
|
|
||||||
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 == ',')
|
|
||||||
str++;
|
|
||||||
else if (*str != '\0')
|
|
||||||
goto bad_format;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf_finalize(buf);
|
|
||||||
|
|
||||||
bad_format:
|
|
||||||
elog(ERROR, "invalid input for txid_snapshot: \"%s\"", str_start);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Public functions.
|
|
||||||
*
|
|
||||||
* txid_current() and txid_current_snapshot() are the only ones that
|
|
||||||
* communicate with core xid machinery. All the others work on data
|
|
||||||
* returned by them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_current() returns int8
|
|
||||||
*
|
|
||||||
* Return the current toplevel transaction ID as TXID
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_current(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
txid val;
|
|
||||||
TxidEpoch state;
|
|
||||||
|
|
||||||
load_xid_epoch(&state);
|
|
||||||
|
|
||||||
val = convert_xid(GetTopTransactionId(), &state);
|
|
||||||
|
|
||||||
PG_RETURN_INT64(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_current_snapshot() returns txid_snapshot
|
|
||||||
*
|
|
||||||
* Return current snapshot in TXID format
|
|
||||||
*
|
|
||||||
* Note that only top-transaction XIDs are included in the snapshot.
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_current_snapshot(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap;
|
|
||||||
uint32 nxip, i, size;
|
|
||||||
TxidEpoch state;
|
|
||||||
Snapshot cur;
|
|
||||||
|
|
||||||
cur = ActiveSnapshot;
|
|
||||||
if (cur == NULL)
|
|
||||||
elog(ERROR, "txid_current_snapshot: ActiveSnapshot == NULL");
|
|
||||||
|
|
||||||
load_xid_epoch(&state);
|
|
||||||
|
|
||||||
/* allocate */
|
|
||||||
nxip = cur->xcnt;
|
|
||||||
size = TXID_SNAPSHOT_SIZE(nxip);
|
|
||||||
snap = palloc(size);
|
|
||||||
SET_VARSIZE(snap, size);
|
|
||||||
|
|
||||||
/* fill */
|
|
||||||
snap->xmin = convert_xid(cur->xmin, &state);
|
|
||||||
snap->xmax = convert_xid(cur->xmax, &state);
|
|
||||||
snap->nxip = nxip;
|
|
||||||
for (i = 0; i < nxip; i++)
|
|
||||||
snap->xip[i] = convert_xid(cur->xip[i], &state);
|
|
||||||
|
|
||||||
/* we want them guaranteed to be in ascending order */
|
|
||||||
sort_snapshot(snap);
|
|
||||||
|
|
||||||
PG_RETURN_POINTER(snap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_in(cstring) returns txid_snapshot
|
|
||||||
*
|
|
||||||
* input function for type txid_snapshot
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_in(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
char *str = PG_GETARG_CSTRING(0);
|
|
||||||
TxidSnapshot *snap;
|
|
||||||
|
|
||||||
snap = parse_snapshot(str);
|
|
||||||
|
|
||||||
PG_RETURN_POINTER(snap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_out(txid_snapshot) returns cstring
|
|
||||||
*
|
|
||||||
* output function for type txid_snapshot
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_out(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
|
||||||
StringInfoData str;
|
|
||||||
uint32 i;
|
|
||||||
|
|
||||||
initStringInfo(&str);
|
|
||||||
|
|
||||||
appendStringInfo(&str, TXID_FMT ":", snap->xmin);
|
|
||||||
appendStringInfo(&str, TXID_FMT ":", snap->xmax);
|
|
||||||
|
|
||||||
for (i = 0; i < snap->nxip; i++)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
appendStringInfoChar(&str, ',');
|
|
||||||
appendStringInfo(&str, TXID_FMT, snap->xip[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_CSTRING(str.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_recv(internal) returns txid_snapshot
|
|
||||||
*
|
|
||||||
* binary input function for type txid_snapshot
|
|
||||||
*
|
|
||||||
* format: int4 nxip, int8 xmin, int8 xmax, int8 xip
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_recv(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
||||||
TxidSnapshot *snap;
|
|
||||||
txid last = 0;
|
|
||||||
int nxip;
|
|
||||||
int i;
|
|
||||||
int avail;
|
|
||||||
int expect;
|
|
||||||
txid xmin, xmax;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* load nxip and check for nonsense.
|
|
||||||
*
|
|
||||||
* (nxip > avail) check is against int overflows in 'expect'.
|
|
||||||
*/
|
|
||||||
nxip = pq_getmsgint(buf, 4);
|
|
||||||
avail = buf->len - buf->cursor;
|
|
||||||
expect = 8 + 8 + nxip * 8;
|
|
||||||
if (nxip < 0 || nxip > avail || expect > avail)
|
|
||||||
goto bad_format;
|
|
||||||
|
|
||||||
xmin = pq_getmsgint64(buf);
|
|
||||||
xmax = pq_getmsgint64(buf);
|
|
||||||
if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID)
|
|
||||||
goto bad_format;
|
|
||||||
|
|
||||||
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:
|
|
||||||
elog(ERROR, "invalid snapshot data");
|
|
||||||
return (Datum)NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_send(txid_snapshot) returns bytea
|
|
||||||
*
|
|
||||||
* binary output function for type txid_snapshot
|
|
||||||
*
|
|
||||||
* format: int4 nxip, int8 xmin, int8 xmax, int8 xip
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_send(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *)PG_GETARG_VARLENA_P(0);
|
|
||||||
StringInfoData buf;
|
|
||||||
uint32 i;
|
|
||||||
|
|
||||||
pq_begintypsend(&buf);
|
|
||||||
pq_sendint(&buf, snap->nxip, 4);
|
|
||||||
pq_sendint64(&buf, snap->xmin);
|
|
||||||
pq_sendint64(&buf, snap->xmax);
|
|
||||||
for (i = 0; i < snap->nxip; i++)
|
|
||||||
pq_sendint64(&buf, snap->xip[i]);
|
|
||||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_visible_in_snapshot(int8, txid_snapshot) returns bool
|
|
||||||
*
|
|
||||||
* is txid visible in snapshot ?
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_visible_in_snapshot(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
txid value = PG_GETARG_INT64(0);
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(is_visible_txid(value, snap));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_xmin(txid_snapshot) returns int8
|
|
||||||
*
|
|
||||||
* return snapshot's xmin
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_xmin(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
|
||||||
|
|
||||||
PG_RETURN_INT64(snap->xmin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_xmax(txid_snapshot) returns int8
|
|
||||||
*
|
|
||||||
* return snapshot's xmax
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_xmax(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
|
||||||
|
|
||||||
PG_RETURN_INT64(snap->xmax);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* txid_snapshot_xip(txid_snapshot) returns setof int8
|
|
||||||
*
|
|
||||||
* return in-progress TXIDs in snapshot.
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
txid_snapshot_xip(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
FuncCallContext *fctx;
|
|
||||||
TxidSnapshot *snap;
|
|
||||||
txid value;
|
|
||||||
|
|
||||||
/* on first call initialize snap_state and get copy of snapshot */
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
|
||||||
TxidSnapshot *arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
|
||||||
|
|
||||||
fctx = SRF_FIRSTCALL_INIT();
|
|
||||||
|
|
||||||
/* make a copy of user snapshot */
|
|
||||||
snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
|
|
||||||
memcpy(snap, arg, VARSIZE(arg));
|
|
||||||
|
|
||||||
fctx->user_fctx = snap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return values one-by-one */
|
|
||||||
fctx = SRF_PERCALL_SETUP();
|
|
||||||
snap = fctx->user_fctx;
|
|
||||||
if (fctx->call_cntr < snap->nxip) {
|
|
||||||
value = snap->xip[fctx->call_cntr];
|
|
||||||
SRF_RETURN_NEXT(fctx, Int64GetDatum(value));
|
|
||||||
} else {
|
|
||||||
SRF_RETURN_DONE(fctx);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
-- ----------
|
|
||||||
-- txid.sql
|
|
||||||
--
|
|
||||||
-- SQL script for loading the transaction ID compatible datatype
|
|
||||||
--
|
|
||||||
-- Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
|
||||||
-- Author: Jan Wieck, Afilias USA INC.
|
|
||||||
-- 64-bit txids: Marko Kreen, Skype Technologies
|
|
||||||
--
|
|
||||||
-- $PostgreSQL: pgsql/contrib/txid/txid.sql.in,v 1.2 2007/10/11 19:54:17 tgl Exp $
|
|
||||||
--
|
|
||||||
-- ----------
|
|
||||||
|
|
||||||
-- Adjust this setting to control where the objects get created.
|
|
||||||
SET search_path = public;
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- A special transaction snapshot data type for faster visibility checks
|
|
||||||
--
|
|
||||||
CREATE TYPE txid_snapshot;
|
|
||||||
|
|
||||||
CREATE FUNCTION txid_snapshot_in(cstring)
|
|
||||||
RETURNS txid_snapshot
|
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
CREATE FUNCTION txid_snapshot_out(txid_snapshot)
|
|
||||||
RETURNS cstring
|
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
CREATE FUNCTION txid_snapshot_recv(internal)
|
|
||||||
RETURNS txid_snapshot
|
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
CREATE FUNCTION txid_snapshot_send(txid_snapshot)
|
|
||||||
RETURNS bytea
|
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- The data type itself
|
|
||||||
--
|
|
||||||
CREATE TYPE txid_snapshot (
|
|
||||||
INPUT = txid_snapshot_in,
|
|
||||||
OUTPUT = txid_snapshot_out,
|
|
||||||
RECEIVE = txid_snapshot_recv,
|
|
||||||
SEND = txid_snapshot_send,
|
|
||||||
INTERNALLENGTH = variable,
|
|
||||||
STORAGE = extended,
|
|
||||||
ALIGNMENT = double
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Functions for txid
|
|
||||||
--
|
|
||||||
CREATE FUNCTION txid_current()
|
|
||||||
RETURNS bigint
|
|
||||||
AS 'MODULE_PATHNAME', 'txid_current' LANGUAGE C
|
|
||||||
STABLE;
|
|
||||||
|
|
||||||
CREATE FUNCTION txid_current_snapshot()
|
|
||||||
RETURNS txid_snapshot
|
|
||||||
AS 'MODULE_PATHNAME', 'txid_current_snapshot' LANGUAGE C
|
|
||||||
STABLE;
|
|
||||||
|
|
||||||
CREATE FUNCTION txid_snapshot_xmin(txid_snapshot)
|
|
||||||
RETURNS bigint
|
|
||||||
AS 'MODULE_PATHNAME', 'txid_snapshot_xmin' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION txid_snapshot_xmax(txid_snapshot)
|
|
||||||
RETURNS bigint
|
|
||||||
AS 'MODULE_PATHNAME', 'txid_snapshot_xmax' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION txid_snapshot_xip(txid_snapshot)
|
|
||||||
RETURNS setof bigint
|
|
||||||
AS 'MODULE_PATHNAME', 'txid_snapshot_xip' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION txid_visible_in_snapshot(bigint, txid_snapshot)
|
|
||||||
RETURNS boolean
|
|
||||||
AS 'MODULE_PATHNAME', 'txid_visible_in_snapshot' LANGUAGE C
|
|
||||||
IMMUTABLE STRICT;
|
|
||||||
|
|
||||||
COMMIT;
|
|
@ -1,11 +0,0 @@
|
|||||||
SET search_path = public;
|
|
||||||
|
|
||||||
DROP FUNCTION txid_current();
|
|
||||||
DROP FUNCTION txid_current_snapshot();
|
|
||||||
DROP FUNCTION txid_snapshot_xmin(txid_snapshot);
|
|
||||||
DROP FUNCTION txid_snapshot_xmax(txid_snapshot);
|
|
||||||
DROP FUNCTION txid_snapshot_xip(txid_snapshot);
|
|
||||||
DROP FUNCTION txid_visible_in_snapshot(bigint, txid_snapshot);
|
|
||||||
|
|
||||||
DROP TYPE txid_snapshot CASCADE;
|
|
||||||
-- need cascade to drop the I/O functions
|
|
Loading…
x
Reference in New Issue
Block a user