mirror of
https://github.com/postgres/postgres.git
synced 2026-07-15 12:51:05 -04:00
Add tid_block() and tid_offset() accessor functions
The two new functions allow to extract the block number and offset from a tid. There are existing ways to do so (e.g. by doing (ctid::text::point)[0]), but they are hard to remember and not pretty. tid_block() returns int8 (bigint) because BlockNumber is uint32, which exceeds the range of int4. tid_offset() returns int4 (integer) because OffsetNumber is uint16, which fits safely in int4. Bumps catversion. Author: Ayush Tiwari <ayushtiwari.slg01@gmail.com> Discussion: https://postgr.es/m/CAJTYsWUzok2+mvSYkbVUwq_SWWg-GdHqCuYumN82AU97SjwjCA@mail.gmail.com
This commit is contained in:
parent
f10b6be258
commit
df6949ccf7
9 changed files with 197 additions and 1 deletions
|
|
@ -17,6 +17,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY func-formatting SYSTEM "func-formatting.sgml">
|
||||
<!ENTITY func-datetime SYSTEM "func-datetime.sgml">
|
||||
<!ENTITY func-enum SYSTEM "func-enum.sgml">
|
||||
<!ENTITY func-tid SYSTEM "func-tid.sgml">
|
||||
<!ENTITY func-geometry SYSTEM "func-geometry.sgml">
|
||||
<!ENTITY func-net SYSTEM "func-net.sgml">
|
||||
<!ENTITY func-textsearch SYSTEM "func-textsearch.sgml">
|
||||
|
|
|
|||
70
doc/src/sgml/func/func-tid.sgml
Normal file
70
doc/src/sgml/func/func-tid.sgml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<sect1 id="functions-tid">
|
||||
<title>TID Functions</title>
|
||||
|
||||
<indexterm zone="functions-tid">
|
||||
<primary>TID</primary>
|
||||
<secondary>functions</secondary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>tid_block</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>tid_offset</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
<xref linkend="functions-tid-table"/> lists functions for
|
||||
the <type>tid</type> data type (tuple identifier).
|
||||
</para>
|
||||
|
||||
<table id="functions-tid-table">
|
||||
<title><acronym>TID</acronym> Functions</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
Function
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para>
|
||||
<para>
|
||||
Example(s)
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>tid_block</function> ( <type>tid</type> )
|
||||
<returnvalue>bigint</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Extracts the block number from a tuple identifier.
|
||||
</para>
|
||||
<para>
|
||||
<literal>tid_block('(42,7)'::tid)</literal>
|
||||
<returnvalue>42</returnvalue>
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>tid_offset</function> ( <type>tid</type> )
|
||||
<returnvalue>integer</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Extracts the tuple offset within the block from a tuple identifier.
|
||||
</para>
|
||||
<para>
|
||||
<literal>tid_offset('(42,7)'::tid)</literal>
|
||||
<returnvalue>7</returnvalue>
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
|
@ -62,6 +62,7 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
|
|||
&func-geometry;
|
||||
&func-net;
|
||||
&func-textsearch;
|
||||
&func-tid;
|
||||
&func-uuid;
|
||||
&func-xml;
|
||||
&func-json;
|
||||
|
|
|
|||
|
|
@ -279,6 +279,35 @@ hashtidextended(PG_FUNCTION_ARGS)
|
|||
seed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the block number from a TID
|
||||
*
|
||||
* Returns int8 because BlockNumber is uint32, which exceeds the range of int4.
|
||||
*/
|
||||
Datum
|
||||
tid_block(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ItemPointer tid = PG_GETARG_ITEMPOINTER(0);
|
||||
|
||||
/* need to use NoCheck, as tidin allows InvalidBlockNumber */
|
||||
PG_RETURN_INT64((int64) ItemPointerGetBlockNumberNoCheck(tid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the offset number from a TID
|
||||
*
|
||||
* Returns int4 because OffsetNumber is uint16, which exceeds the range of
|
||||
* int2.
|
||||
*/
|
||||
Datum
|
||||
tid_offset(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ItemPointer tid = PG_GETARG_ITEMPOINTER(0);
|
||||
|
||||
/* need to use NoCheck, as tidin allows InvalidOffsetNumber */
|
||||
PG_RETURN_INT32((int32) ItemPointerGetOffsetNumberNoCheck(tid));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Functions to get latest tid of a specified tuple.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202604031
|
||||
#define CATALOG_VERSION_NO 202604051
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2757,6 +2757,12 @@
|
|||
{ oid => '2796', descr => 'smaller of two',
|
||||
proname => 'tidsmaller', prorettype => 'tid', proargtypes => 'tid tid',
|
||||
prosrc => 'tidsmaller' },
|
||||
{ oid => '9951', descr => 'extract block number from tid',
|
||||
proname => 'tid_block', proleakproof => 't', prorettype => 'int8',
|
||||
proargtypes => 'tid', prosrc => 'tid_block' },
|
||||
{ oid => '9952', descr => 'extract offset number from tid',
|
||||
proname => 'tid_offset', proleakproof => 't', prorettype => 'int4',
|
||||
proargtypes => 'tid', prosrc => 'tid_offset' },
|
||||
{ oid => '2233', descr => 'hash',
|
||||
proname => 'hashtid', prorettype => 'int4', proargtypes => 'tid',
|
||||
prosrc => 'hashtid' },
|
||||
|
|
|
|||
|
|
@ -887,6 +887,8 @@ oid8le(oid8,oid8)
|
|||
oid8gt(oid8,oid8)
|
||||
oid8ge(oid8,oid8)
|
||||
btoid8cmp(oid8,oid8)
|
||||
tid_block(tid)
|
||||
tid_offset(tid)
|
||||
-- Check that functions without argument are not marked as leakproof.
|
||||
SELECT p1.oid::regprocedure
|
||||
FROM pg_proc p1 JOIN pg_namespace pn
|
||||
|
|
|
|||
|
|
@ -42,6 +42,57 @@ SELECT * FROM pg_input_error_info('(0,-1)', 'tid');
|
|||
invalid input syntax for type tid: "(0,-1)" | | | 22P02
|
||||
(1 row)
|
||||
|
||||
-- tests for tid_block() and tid_offset()
|
||||
SELECT tid_block('(0,0)'::tid), tid_offset('(0,0)'::tid);
|
||||
tid_block | tid_offset
|
||||
-----------+------------
|
||||
0 | 0
|
||||
(1 row)
|
||||
|
||||
SELECT tid_block('(0,1)'::tid), tid_offset('(0,1)'::tid);
|
||||
tid_block | tid_offset
|
||||
-----------+------------
|
||||
0 | 1
|
||||
(1 row)
|
||||
|
||||
SELECT tid_block('(42,7)'::tid), tid_offset('(42,7)'::tid);
|
||||
tid_block | tid_offset
|
||||
-----------+------------
|
||||
42 | 7
|
||||
(1 row)
|
||||
|
||||
-- max values: blockno uint32 max, offset uint16 max
|
||||
SELECT tid_block('(4294967295,65535)'::tid), tid_offset('(4294967295,65535)'::tid);
|
||||
tid_block | tid_offset
|
||||
------------+------------
|
||||
4294967295 | 65535
|
||||
(1 row)
|
||||
|
||||
-- (-1,0) wraps to blockno 4294967295
|
||||
SELECT tid_block('(-1,0)'::tid);
|
||||
tid_block
|
||||
------------
|
||||
4294967295
|
||||
(1 row)
|
||||
|
||||
-- NULL handling (strict functions)
|
||||
SELECT tid_block(NULL::tid), tid_offset(NULL::tid);
|
||||
tid_block | tid_offset
|
||||
-----------+------------
|
||||
|
|
||||
(1 row)
|
||||
|
||||
-- round-trip: blockno + offset reconstruct the original TID
|
||||
SELECT t, tid_block(t), tid_offset(t),
|
||||
format('(%s,%s)', tid_block(t), tid_offset(t))::tid = t AS roundtrip_ok
|
||||
FROM (VALUES ('(0,0)'::tid), ('(1,42)'::tid), ('(4294967295,65535)'::tid)) AS v(t);
|
||||
t | tid_block | tid_offset | roundtrip_ok
|
||||
--------------------+------------+------------+--------------
|
||||
(0,0) | 0 | 0 | t
|
||||
(1,42) | 1 | 42 | t
|
||||
(4294967295,65535) | 4294967295 | 65535 | t
|
||||
(3 rows)
|
||||
|
||||
-- tests for functions related to TID handling
|
||||
CREATE TABLE tid_tab (a int);
|
||||
-- min() and max() for TIDs
|
||||
|
|
@ -58,6 +109,21 @@ SELECT max(ctid) FROM tid_tab;
|
|||
(0,2)
|
||||
(1 row)
|
||||
|
||||
-- tid_block() and tid_offset() with real table ctid
|
||||
SELECT ctid, tid_block(ctid), tid_offset(ctid) FROM tid_tab;
|
||||
ctid | tid_block | tid_offset
|
||||
-------+-----------+------------
|
||||
(0,1) | 0 | 1
|
||||
(0,2) | 0 | 2
|
||||
(2 rows)
|
||||
|
||||
-- use in WHERE clause
|
||||
SELECT ctid FROM tid_tab WHERE tid_block(ctid) = 0 AND tid_offset(ctid) = 1;
|
||||
ctid
|
||||
-------
|
||||
(0,1)
|
||||
(1 row)
|
||||
|
||||
TRUNCATE tid_tab;
|
||||
-- Tests for currtid2() with various relation kinds
|
||||
-- Materialized view
|
||||
|
|
|
|||
|
|
@ -16,6 +16,22 @@ SELECT pg_input_is_valid('(0,-1)', 'tid');
|
|||
SELECT * FROM pg_input_error_info('(0,-1)', 'tid');
|
||||
|
||||
|
||||
-- tests for tid_block() and tid_offset()
|
||||
SELECT tid_block('(0,0)'::tid), tid_offset('(0,0)'::tid);
|
||||
SELECT tid_block('(0,1)'::tid), tid_offset('(0,1)'::tid);
|
||||
SELECT tid_block('(42,7)'::tid), tid_offset('(42,7)'::tid);
|
||||
-- max values: blockno uint32 max, offset uint16 max
|
||||
SELECT tid_block('(4294967295,65535)'::tid), tid_offset('(4294967295,65535)'::tid);
|
||||
-- (-1,0) wraps to blockno 4294967295
|
||||
SELECT tid_block('(-1,0)'::tid);
|
||||
-- NULL handling (strict functions)
|
||||
SELECT tid_block(NULL::tid), tid_offset(NULL::tid);
|
||||
-- round-trip: blockno + offset reconstruct the original TID
|
||||
SELECT t, tid_block(t), tid_offset(t),
|
||||
format('(%s,%s)', tid_block(t), tid_offset(t))::tid = t AS roundtrip_ok
|
||||
FROM (VALUES ('(0,0)'::tid), ('(1,42)'::tid), ('(4294967295,65535)'::tid)) AS v(t);
|
||||
|
||||
|
||||
-- tests for functions related to TID handling
|
||||
|
||||
CREATE TABLE tid_tab (a int);
|
||||
|
|
@ -24,6 +40,11 @@ CREATE TABLE tid_tab (a int);
|
|||
INSERT INTO tid_tab VALUES (1), (2);
|
||||
SELECT min(ctid) FROM tid_tab;
|
||||
SELECT max(ctid) FROM tid_tab;
|
||||
|
||||
-- tid_block() and tid_offset() with real table ctid
|
||||
SELECT ctid, tid_block(ctid), tid_offset(ctid) FROM tid_tab;
|
||||
-- use in WHERE clause
|
||||
SELECT ctid FROM tid_tab WHERE tid_block(ctid) = 0 AND tid_offset(ctid) = 1;
|
||||
TRUNCATE tid_tab;
|
||||
|
||||
-- Tests for currtid2() with various relation kinds
|
||||
|
|
|
|||
Loading…
Reference in a new issue