Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
d6061f83
Commit
d6061f83
authored
Nov 25, 2015
by
Teodor Sigaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve pageinspect module
Now pageinspect can show data stored in the heap tuple. Nikolay Shaplov
parent
13b30c16
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
411 additions
and
19 deletions
+411
-19
contrib/pageinspect/Makefile
contrib/pageinspect/Makefile
+3
-3
contrib/pageinspect/heapfuncs.c
contrib/pageinspect/heapfuncs.c
+261
-10
contrib/pageinspect/pageinspect--1.4.sql
contrib/pageinspect/pageinspect--1.4.sql
+92
-2
contrib/pageinspect/pageinspect.control
contrib/pageinspect/pageinspect.control
+1
-1
doc/src/sgml/pageinspect.sgml
doc/src/sgml/pageinspect.sgml
+54
-3
No files found.
contrib/pageinspect/Makefile
View file @
d6061f83
...
@@ -5,9 +5,9 @@ OBJS = rawpage.o heapfuncs.o btreefuncs.o fsmfuncs.o \
...
@@ -5,9 +5,9 @@ OBJS = rawpage.o heapfuncs.o btreefuncs.o fsmfuncs.o \
brinfuncs.o ginfuncs.o
$(WIN32RES)
brinfuncs.o ginfuncs.o
$(WIN32RES)
EXTENSION
=
pageinspect
EXTENSION
=
pageinspect
DATA
=
pageinspect--1.
3.sql pageinspect--1.2--1.3
.sql
\
DATA
=
pageinspect--1.
4.sql pageinspect--1.3--1.4
.sql
\
pageinspect--1.
1--1.2.sql pageinspect--1.0--1.1
.sql
\
pageinspect--1.
2--1.3.sql pageinspect--1.1--1.2
.sql
\
pageinspect--unpackaged--1.0.sql
pageinspect--
1.0--1.1.sql pageinspect--
unpackaged--1.0.sql
PGFILEDESC
=
"pageinspect - functions to inspect contents of database pages"
PGFILEDESC
=
"pageinspect - functions to inspect contents of database pages"
ifdef
USE_PGXS
ifdef
USE_PGXS
...
...
contrib/pageinspect/heapfuncs.c
View file @
d6061f83
...
@@ -27,8 +27,11 @@
...
@@ -27,8 +27,11 @@
#include "access/htup_details.h"
#include "access/htup_details.h"
#include "funcapi.h"
#include "funcapi.h"
#include "
utils/builtins
.h"
#include "
catalog/pg_type
.h"
#include "miscadmin.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/rel.h"
/*
/*
...
@@ -54,6 +57,42 @@ bits_to_text(bits8 *bits, int len)
...
@@ -54,6 +57,42 @@ bits_to_text(bits8 *bits, int len)
}
}
/*
* text_to_bits
*
* Converts a c-string representation of bits into a bits8-array. This is
* the reverse operation of previous routine.
*/
static
bits8
*
text_to_bits
(
char
*
str
,
int
len
)
{
bits8
*
bits
;
int
off
=
0
;
char
byte
=
0
;
bits
=
palloc
(
len
+
1
);
while
(
off
<
len
)
{
if
(
off
%
8
==
0
)
byte
=
0
;
if
((
str
[
off
]
==
'0'
)
||
(
str
[
off
]
==
'1'
))
byte
=
byte
|
((
str
[
off
]
-
'0'
)
<<
off
%
8
);
else
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"illegal character '%c' in t_bits string"
,
str
[
off
])));
if
(
off
%
8
==
7
)
bits
[
off
/
8
]
=
byte
;
off
++
;
}
return
bits
;
}
/*
/*
* heap_page_items
* heap_page_items
*
*
...
@@ -122,8 +161,8 @@ heap_page_items(PG_FUNCTION_ARGS)
...
@@ -122,8 +161,8 @@ heap_page_items(PG_FUNCTION_ARGS)
HeapTuple
resultTuple
;
HeapTuple
resultTuple
;
Datum
result
;
Datum
result
;
ItemId
id
;
ItemId
id
;
Datum
values
[
1
3
];
Datum
values
[
1
4
];
bool
nulls
[
1
3
];
bool
nulls
[
1
4
];
uint16
lp_offset
;
uint16
lp_offset
;
uint16
lp_flags
;
uint16
lp_flags
;
uint16
lp_len
;
uint16
lp_len
;
...
@@ -153,8 +192,9 @@ heap_page_items(PG_FUNCTION_ARGS)
...
@@ -153,8 +192,9 @@ heap_page_items(PG_FUNCTION_ARGS)
lp_offset
==
MAXALIGN
(
lp_offset
)
&&
lp_offset
==
MAXALIGN
(
lp_offset
)
&&
lp_offset
+
lp_len
<=
raw_page_size
)
lp_offset
+
lp_len
<=
raw_page_size
)
{
{
HeapTupleHeader
tuphdr
;
HeapTupleHeader
tuphdr
;
int
bits_len
;
bytea
*
tuple_data_bytea
;
int
tuple_data_len
;
/* Extract information from the tuple header */
/* Extract information from the tuple header */
...
@@ -162,12 +202,21 @@ heap_page_items(PG_FUNCTION_ARGS)
...
@@ -162,12 +202,21 @@ heap_page_items(PG_FUNCTION_ARGS)
values
[
4
]
=
UInt32GetDatum
(
HeapTupleHeaderGetRawXmin
(
tuphdr
));
values
[
4
]
=
UInt32GetDatum
(
HeapTupleHeaderGetRawXmin
(
tuphdr
));
values
[
5
]
=
UInt32GetDatum
(
HeapTupleHeaderGetRawXmax
(
tuphdr
));
values
[
5
]
=
UInt32GetDatum
(
HeapTupleHeaderGetRawXmax
(
tuphdr
));
values
[
6
]
=
UInt32GetDatum
(
HeapTupleHeaderGetRawCommandId
(
tuphdr
));
/* shared with xvac */
/* shared with xvac */
values
[
6
]
=
UInt32GetDatum
(
HeapTupleHeaderGetRawCommandId
(
tuphdr
));
values
[
7
]
=
PointerGetDatum
(
&
tuphdr
->
t_ctid
);
values
[
7
]
=
PointerGetDatum
(
&
tuphdr
->
t_ctid
);
values
[
8
]
=
UInt32GetDatum
(
tuphdr
->
t_infomask2
);
values
[
8
]
=
UInt32GetDatum
(
tuphdr
->
t_infomask2
);
values
[
9
]
=
UInt32GetDatum
(
tuphdr
->
t_infomask
);
values
[
9
]
=
UInt32GetDatum
(
tuphdr
->
t_infomask
);
values
[
10
]
=
UInt8GetDatum
(
tuphdr
->
t_hoff
);
values
[
10
]
=
UInt8GetDatum
(
tuphdr
->
t_hoff
);
/* Copy raw tuple data into bytea attribute */
tuple_data_len
=
lp_len
-
tuphdr
->
t_hoff
;
tuple_data_bytea
=
(
bytea
*
)
palloc
(
tuple_data_len
+
VARHDRSZ
);
SET_VARSIZE
(
tuple_data_bytea
,
tuple_data_len
+
VARHDRSZ
);
memcpy
(
VARDATA
(
tuple_data_bytea
),
(
char
*
)
tuphdr
+
tuphdr
->
t_hoff
,
tuple_data_len
);
values
[
13
]
=
PointerGetDatum
(
tuple_data_bytea
);
/*
/*
* We already checked that the item is completely within the raw
* We already checked that the item is completely within the raw
* page passed to us, with the length given in the line pointer.
* page passed to us, with the length given in the line pointer.
...
@@ -180,11 +229,11 @@ heap_page_items(PG_FUNCTION_ARGS)
...
@@ -180,11 +229,11 @@ heap_page_items(PG_FUNCTION_ARGS)
{
{
if
(
tuphdr
->
t_infomask
&
HEAP_HASNULL
)
if
(
tuphdr
->
t_infomask
&
HEAP_HASNULL
)
{
{
bits_len
=
tuphdr
->
t_hoff
-
int
bits_len
=
offsetof
(
HeapTupleHeaderData
,
t_bits
)
;
((
tuphdr
->
t_infomask2
&
HEAP_NATTS_MASK
)
/
8
+
1
)
*
8
;
values
[
11
]
=
CStringGetTextDatum
(
values
[
11
]
=
CStringGetTextDatum
(
bits_to_text
(
tuphdr
->
t_bits
,
bits_len
*
8
));
bits_to_text
(
tuphdr
->
t_bits
,
bits_len
));
}
}
else
else
nulls
[
11
]
=
true
;
nulls
[
11
]
=
true
;
...
@@ -208,7 +257,7 @@ heap_page_items(PG_FUNCTION_ARGS)
...
@@ -208,7 +257,7 @@ heap_page_items(PG_FUNCTION_ARGS)
*/
*/
int
i
;
int
i
;
for
(
i
=
4
;
i
<=
1
2
;
i
++
)
for
(
i
=
4
;
i
<=
1
3
;
i
++
)
nulls
[
i
]
=
true
;
nulls
[
i
]
=
true
;
}
}
...
@@ -223,3 +272,205 @@ heap_page_items(PG_FUNCTION_ARGS)
...
@@ -223,3 +272,205 @@ heap_page_items(PG_FUNCTION_ARGS)
else
else
SRF_RETURN_DONE
(
fctx
);
SRF_RETURN_DONE
(
fctx
);
}
}
/*
* tuple_data_split_internal
*
* Split raw tuple data taken directly from a page into an array of bytea
* elements. This routine does a lookup on NULL values and creates array
* elements accordindly. This is a reimplementation of nocachegetattr()
* in heaptuple.c simplified for educational purposes.
*/
static
Datum
tuple_data_split_internal
(
Oid
relid
,
char
*
tupdata
,
uint16
tupdata_len
,
uint16
t_infomask
,
uint16
t_infomask2
,
bits8
*
t_bits
,
bool
do_detoast
)
{
ArrayBuildState
*
raw_attrs
;
int
nattrs
;
int
i
;
int
off
=
0
;
Relation
rel
;
TupleDesc
tupdesc
;
/* Get tuple descriptor from relation OID */
rel
=
relation_open
(
relid
,
NoLock
);
tupdesc
=
CreateTupleDescCopyConstr
(
rel
->
rd_att
);
relation_close
(
rel
,
NoLock
);
raw_attrs
=
initArrayResult
(
BYTEAOID
,
CurrentMemoryContext
,
false
);
nattrs
=
tupdesc
->
natts
;
if
(
nattrs
<
(
t_infomask2
&
HEAP_NATTS_MASK
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"number of attributes in tuple header is greater than number of attributes in tuple descriptor"
)));
for
(
i
=
0
;
i
<
nattrs
;
i
++
)
{
Form_pg_attribute
attr
;
bool
is_null
;
bytea
*
attr_data
=
NULL
;
attr
=
tupdesc
->
attrs
[
i
];
is_null
=
(
t_infomask
&
HEAP_HASNULL
)
&&
att_isnull
(
i
,
t_bits
);
/*
* Tuple header can specify less attributes than tuple descriptor
* as ALTER TABLE ADD COLUMN without DEFAULT keyword does not
* actually change tuples in pages, so attributes with numbers greater
* than (t_infomask2 & HEAP_NATTS_MASK) should be treated as NULL.
*/
if
(
i
>=
(
t_infomask2
&
HEAP_NATTS_MASK
))
is_null
=
true
;
if
(
!
is_null
)
{
int
len
;
if
(
attr
->
attlen
==
-
1
)
{
off
=
att_align_pointer
(
off
,
tupdesc
->
attrs
[
i
]
->
attalign
,
-
1
,
tupdata
+
off
);
/*
* As VARSIZE_ANY throws an exception if it can't properly
* detect the type of external storage in macros VARTAG_SIZE,
* this check is repeated to have a nicer error handling.
*/
if
(
VARATT_IS_EXTERNAL
(
tupdata
+
off
)
&&
!
VARATT_IS_EXTERNAL_ONDISK
(
tupdata
+
off
)
&&
!
VARATT_IS_EXTERNAL_INDIRECT
(
tupdata
+
off
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"first byte of varlena attribute is incorrect for attribute %d"
,
i
)));
len
=
VARSIZE_ANY
(
tupdata
+
off
);
}
else
{
off
=
att_align_nominal
(
off
,
tupdesc
->
attrs
[
i
]
->
attalign
);
len
=
attr
->
attlen
;
}
if
(
tupdata_len
<
off
+
len
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"unexpected end of tuple data"
)));
if
(
attr
->
attlen
==
-
1
&&
do_detoast
)
attr_data
=
DatumGetByteaPCopy
(
tupdata
+
off
);
else
{
attr_data
=
(
bytea
*
)
palloc
(
len
+
VARHDRSZ
);
SET_VARSIZE
(
attr_data
,
len
+
VARHDRSZ
);
memcpy
(
VARDATA
(
attr_data
),
tupdata
+
off
,
len
);
}
off
=
att_addlength_pointer
(
off
,
tupdesc
->
attrs
[
i
]
->
attlen
,
tupdata
+
off
);
}
raw_attrs
=
accumArrayResult
(
raw_attrs
,
PointerGetDatum
(
attr_data
),
is_null
,
BYTEAOID
,
CurrentMemoryContext
);
if
(
attr_data
)
pfree
(
attr_data
);
}
if
(
tupdata_len
!=
off
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"end of tuple reached without looking at all its data"
)));
return
makeArrayResult
(
raw_attrs
,
CurrentMemoryContext
);
}
/*
* tuple_data_split
*
* Split raw tuple data taken directly from page into distinct elements
* taking into account null values.
*/
PG_FUNCTION_INFO_V1
(
tuple_data_split
);
Datum
tuple_data_split
(
PG_FUNCTION_ARGS
)
{
Oid
relid
;
bytea
*
raw_data
;
uint16
t_infomask
;
uint16
t_infomask2
;
char
*
t_bits_str
;
bool
do_detoast
=
false
;
bits8
*
t_bits
=
NULL
;
Datum
res
;
relid
=
PG_GETARG_OID
(
0
);
raw_data
=
PG_ARGISNULL
(
1
)
?
NULL
:
PG_GETARG_BYTEA_P
(
1
);
t_infomask
=
PG_GETARG_INT16
(
2
);
t_infomask2
=
PG_GETARG_INT16
(
3
);
t_bits_str
=
PG_ARGISNULL
(
4
)
?
NULL
:
text_to_cstring
(
PG_GETARG_TEXT_PP
(
4
));
if
(
PG_NARGS
()
>=
6
)
do_detoast
=
PG_GETARG_BOOL
(
5
);
if
(
!
superuser
())
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INSUFFICIENT_PRIVILEGE
),
errmsg
(
"must be superuser to use raw page functions"
)));
if
(
!
raw_data
)
PG_RETURN_NULL
();
/*
* Convert t_bits string back to the bits8 array as represented in the
* tuple header.
*/
if
(
t_infomask
&
HEAP_HASNULL
)
{
int
bits_str_len
;
int
bits_len
;
bits_len
=
(
t_infomask2
&
HEAP_NATTS_MASK
)
/
8
+
1
;
if
(
!
t_bits_str
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"argument of t_bits is null, but it is expected to be null and %i character long"
,
bits_len
*
8
)));
bits_str_len
=
strlen
(
t_bits_str
);
if
((
bits_str_len
%
8
)
!=
0
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"length of t_bits is not a multiple of eight"
)));
if
(
bits_len
*
8
!=
bits_str_len
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"unexpected length of t_bits %u, expected %i"
,
bits_str_len
,
bits_len
*
8
)));
/* do the conversion */
t_bits
=
text_to_bits
(
t_bits_str
,
bits_str_len
);
}
else
{
if
(
t_bits_str
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATA_CORRUPTED
),
errmsg
(
"t_bits string is expected to be NULL, but instead it is %lu bytes length"
,
strlen
(
t_bits_str
))));
}
/* Split tuple data */
res
=
tuple_data_split_internal
(
relid
,
(
char
*
)
raw_data
+
VARHDRSZ
,
VARSIZE
(
raw_data
)
-
VARHDRSZ
,
t_infomask
,
t_infomask2
,
t_bits
,
do_detoast
);
if
(
t_bits
)
pfree
(
t_bits
);
PG_RETURN_ARRAYTYPE_P
(
res
);
}
contrib/pageinspect/pageinspect--1.
3
.sql
→
contrib/pageinspect/pageinspect--1.
4
.sql
View file @
d6061f83
/* contrib/pageinspect/pageinspect--1.
3
.sql */
/* contrib/pageinspect/pageinspect--1.
4
.sql */
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\
echo
Use
"CREATE EXTENSION pageinspect"
to
load
this
file
.
\
quit
\
echo
Use
"CREATE EXTENSION pageinspect"
to
load
this
file
.
\
quit
...
@@ -48,11 +48,101 @@ CREATE FUNCTION heap_page_items(IN page bytea,
...
@@ -48,11 +48,101 @@ CREATE FUNCTION heap_page_items(IN page bytea,
OUT
t_infomask
integer
,
OUT
t_infomask
integer
,
OUT
t_hoff
smallint
,
OUT
t_hoff
smallint
,
OUT
t_bits
text
,
OUT
t_bits
text
,
OUT
t_oid
oid
)
OUT
t_oid
oid
,
OUT
t_data
bytea
)
RETURNS
SETOF
record
RETURNS
SETOF
record
AS
'MODULE_PATHNAME'
,
'heap_page_items'
AS
'MODULE_PATHNAME'
,
'heap_page_items'
LANGUAGE
C
STRICT
;
LANGUAGE
C
STRICT
;
--
-- tuple_data_split()
--
CREATE
FUNCTION
tuple_data_split
(
rel_oid
oid
,
t_data
bytea
,
t_infomask
integer
,
t_infomask2
integer
,
t_bits
text
)
RETURNS
bytea
[]
AS
'MODULE_PATHNAME'
,
'tuple_data_split'
LANGUAGE
C
;
CREATE
FUNCTION
tuple_data_split
(
rel_oid
oid
,
t_data
bytea
,
t_infomask
integer
,
t_infomask2
integer
,
t_bits
text
,
do_detoast
bool
)
RETURNS
bytea
[]
AS
'MODULE_PATHNAME'
,
'tuple_data_split'
LANGUAGE
C
;
--
-- heap_page_item_attrs()
--
CREATE
FUNCTION
heap_page_item_attrs
(
IN
page
bytea
,
IN
rel_oid
regclass
,
IN
do_detoast
bool
,
OUT
lp
smallint
,
OUT
lp_off
smallint
,
OUT
lp_flags
smallint
,
OUT
lp_len
smallint
,
OUT
t_xmin
xid
,
OUT
t_xmax
xid
,
OUT
t_field3
int4
,
OUT
t_ctid
tid
,
OUT
t_infomask2
integer
,
OUT
t_infomask
integer
,
OUT
t_hoff
smallint
,
OUT
t_bits
text
,
OUT
t_oid
oid
,
OUT
t_attrs
bytea
[]
)
RETURNS
SETOF
record
AS
$$
SELECT
lp
,
lp_off
,
lp_flags
,
lp_len
,
t_xmin
,
t_xmax
,
t_field3
,
t_ctid
,
t_infomask2
,
t_infomask
,
t_hoff
,
t_bits
,
t_oid
,
tuple_data_split
(
rel_oid
,
t_data
,
t_infomask
,
t_infomask2
,
t_bits
,
do_detoast
)
AS
t_attrs
FROM
heap_page_items
(
page
);
$$
LANGUAGE
SQL
;
CREATE
FUNCTION
heap_page_item_attrs
(
IN
page
bytea
,
IN
rel_oid
regclass
,
OUT
lp
smallint
,
OUT
lp_off
smallint
,
OUT
lp_flags
smallint
,
OUT
lp_len
smallint
,
OUT
t_xmin
xid
,
OUT
t_xmax
xid
,
OUT
t_field3
int4
,
OUT
t_ctid
tid
,
OUT
t_infomask2
integer
,
OUT
t_infomask
integer
,
OUT
t_hoff
smallint
,
OUT
t_bits
text
,
OUT
t_oid
oid
,
OUT
t_attrs
bytea
[]
)
RETURNS
SETOF
record
AS
$$
SELECT
*
from
heap_page_item_attrs
(
page
,
rel_oid
,
false
);
$$
LANGUAGE
SQL
;
--
--
-- bt_metap()
-- bt_metap()
--
--
...
...
contrib/pageinspect/pageinspect.control
View file @
d6061f83
# pageinspect extension
# pageinspect extension
comment = 'inspect the contents of database pages at a low level'
comment = 'inspect the contents of database pages at a low level'
default_version = '1.
3
'
default_version = '1.
4
'
module_pathname = '$libdir/pageinspect'
module_pathname = '$libdir/pageinspect'
relocatable = true
relocatable = true
doc/src/sgml/pageinspect.sgml
View file @
d6061f83
...
@@ -93,9 +93,10 @@ test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
...
@@ -93,9 +93,10 @@ test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
<listitem>
<listitem>
<para>
<para>
<function>heap_page_items</function> shows all line pointers on a heap
<function>heap_page_items</function> shows all line pointers on a heap
page. For those line pointers that are in use, tuple headers are also
page. For those line pointers that are in use, tuple headers as well
shown. All tuples are shown, whether or not the tuples were visible to
as tuple raw data are also shown. All tuples are shown, whether or not
an MVCC snapshot at the time the raw page was copied.
the tuples were visible to an MVCC snapshot at the time the raw page
was copied.
</para>
</para>
<para>
<para>
A heap page image obtained with <function>get_raw_page</function> should
A heap page image obtained with <function>get_raw_page</function> should
...
@@ -110,6 +111,56 @@ test=# SELECT * FROM heap_page_items(get_raw_page('pg_class', 0));
...
@@ -110,6 +111,56 @@ test=# SELECT * FROM heap_page_items(get_raw_page('pg_class', 0));
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<term>
<function>tuple_data_split(rel_oid, t_data bytea, t_infomask integer, t_infomask2 integer, t_bits text [, do_detoast bool]) returns bytea[]</function>
<indexterm>
<primary>tuple_data_split</primary>
</indexterm>
</term>
<listitem>
<para>
<function>tuple_data_split</function> splits tuple data into attributes
in the same way as backend internals.
<screen>
test=# SELECT tuple_data_split('pg_class'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('pg_class', 0));
</screen>
This function should be called with the same arguments as the return
attributes of <function>heap_page_items</function>.
</para>
<para>
If <parameter>do_detoast</parameter> is <literal>true</literal>,
attribute that will be detoasted as needed. Default value is
<literal>false</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>heap_page_item_attrs(rel_oid, t_data bytea, [, do_detoast bool]) returns bytea[]</function>
<indexterm>
<primary>heap_page_item_attrs</primary>
</indexterm>
</term>
<listitem>
<para>
<function>heap_page_item_attrs</function> is equivalent to
<function>heap_page_items</function> except that it returns
tuple raw data as an array of attributes that can optionally
be detoasted by <parameter>do_detoast</parameter> which is
<literal>false</literal> by default.
</para>
<para>
A heap page image obtained with <function>get_raw_page</function> should
be passed as argument. For example:
<screen>
test=# SELECT * FROM heap_page_item_attrs(get_raw_page('pg_class', 0), 'pg_class'::regclass);
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term>
<term>
<function>bt_metap(relname text) returns record</function>
<function>bt_metap(relname text) returns record</function>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment