Add pg_column_toast_chunk_id().
This function returns the chunk_id of an on-disk TOASTed value. If the value is un-TOASTed or not on-disk, it returns NULL. This is useful for identifying which values are actually TOASTed and for investigating "unexpected chunk number" errors. Bumps catversion. Author: Yugo Nagata Reviewed-by: Jian He Discussion: https://postgr.es/m/20230329105507.d764497456eeac1ca491b5bd%40sraoss.co.jp
This commit is contained in:
parent
84c18acaf6
commit
d1162cfda8
|
@ -28552,6 +28552,23 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
|
||||||
</para></entry>
|
</para></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
|
<indexterm>
|
||||||
|
<primary>pg_column_toast_chunk_id</primary>
|
||||||
|
</indexterm>
|
||||||
|
<function>pg_column_toast_chunk_id</function> ( <type>"any"</type> )
|
||||||
|
<returnvalue>oid</returnvalue>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Shows the <structfield>chunk_id</structfield> of an on-disk
|
||||||
|
<acronym>TOAST</acronym>ed value. Returns <literal>NULL</literal>
|
||||||
|
if the value is un-<acronym>TOAST</acronym>ed or not on-disk. See
|
||||||
|
<xref linkend="storage-toast"/> for more information about
|
||||||
|
<acronym>TOAST</acronym>.
|
||||||
|
</para></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry role="func_table_entry"><para role="func_signature">
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
<indexterm>
|
<indexterm>
|
||||||
|
|
|
@ -5105,6 +5105,47 @@ pg_column_compression(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_TEXT_P(cstring_to_text(result));
|
PG_RETURN_TEXT_P(cstring_to_text(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the chunk_id of the on-disk TOASTed value. Return NULL if the value
|
||||||
|
* is un-TOASTed or not on-disk.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_column_toast_chunk_id(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
int typlen;
|
||||||
|
struct varlena *attr;
|
||||||
|
struct varatt_external toast_pointer;
|
||||||
|
|
||||||
|
/* On first call, get the input type's typlen, and save at *fn_extra */
|
||||||
|
if (fcinfo->flinfo->fn_extra == NULL)
|
||||||
|
{
|
||||||
|
/* Lookup the datatype of the supplied argument */
|
||||||
|
Oid argtypeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||||
|
|
||||||
|
typlen = get_typlen(argtypeid);
|
||||||
|
if (typlen == 0) /* should not happen */
|
||||||
|
elog(ERROR, "cache lookup failed for type %u", argtypeid);
|
||||||
|
|
||||||
|
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
|
||||||
|
sizeof(int));
|
||||||
|
*((int *) fcinfo->flinfo->fn_extra) = typlen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
typlen = *((int *) fcinfo->flinfo->fn_extra);
|
||||||
|
|
||||||
|
if (typlen != -1)
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
|
attr = (struct varlena *) DatumGetPointer(PG_GETARG_DATUM(0));
|
||||||
|
|
||||||
|
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
|
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
|
||||||
|
|
||||||
|
PG_RETURN_OID(toast_pointer.va_valueid);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* string_agg - Concatenates values and returns string.
|
* string_agg - Concatenates values and returns string.
|
||||||
*
|
*
|
||||||
|
|
|
@ -57,6 +57,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 202403132
|
#define CATALOG_VERSION_NO 202403141
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7447,6 +7447,9 @@
|
||||||
{ oid => '2121', descr => 'compression method for the compressed datum',
|
{ oid => '2121', descr => 'compression method for the compressed datum',
|
||||||
proname => 'pg_column_compression', provolatile => 's', prorettype => 'text',
|
proname => 'pg_column_compression', provolatile => 's', prorettype => 'text',
|
||||||
proargtypes => 'any', prosrc => 'pg_column_compression' },
|
proargtypes => 'any', prosrc => 'pg_column_compression' },
|
||||||
|
{ oid => '8393', descr => 'chunk ID of on-disk TOASTed value',
|
||||||
|
proname => 'pg_column_toast_chunk_id', provolatile => 's', prorettype => 'oid',
|
||||||
|
proargtypes => 'any', prosrc => 'pg_column_toast_chunk_id' },
|
||||||
{ oid => '2322',
|
{ oid => '2322',
|
||||||
descr => 'total disk space usage for the specified tablespace',
|
descr => 'total disk space usage for the specified tablespace',
|
||||||
proname => 'pg_tablespace_size', provolatile => 'v', prorettype => 'int8',
|
proname => 'pg_tablespace_size', provolatile => 'v', prorettype => 'int8',
|
||||||
|
|
|
@ -703,3 +703,19 @@ SELECT has_function_privilege('regress_current_logfile',
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP ROLE regress_current_logfile;
|
DROP ROLE regress_current_logfile;
|
||||||
|
-- pg_column_toast_chunk_id
|
||||||
|
CREATE TABLE test_chunk_id (a TEXT, b TEXT STORAGE EXTERNAL);
|
||||||
|
INSERT INTO test_chunk_id VALUES ('x', repeat('x', 8192));
|
||||||
|
SELECT t.relname AS toastrel FROM pg_class c
|
||||||
|
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
|
||||||
|
WHERE c.relname = 'test_chunk_id'
|
||||||
|
\gset
|
||||||
|
SELECT pg_column_toast_chunk_id(a) IS NULL,
|
||||||
|
pg_column_toast_chunk_id(b) IN (SELECT chunk_id FROM pg_toast.:toastrel)
|
||||||
|
FROM test_chunk_id;
|
||||||
|
?column? | ?column?
|
||||||
|
----------+----------
|
||||||
|
t | t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE test_chunk_id;
|
||||||
|
|
|
@ -265,3 +265,15 @@ GRANT pg_monitor TO regress_current_logfile;
|
||||||
SELECT has_function_privilege('regress_current_logfile',
|
SELECT has_function_privilege('regress_current_logfile',
|
||||||
'pg_current_logfile()', 'EXECUTE');
|
'pg_current_logfile()', 'EXECUTE');
|
||||||
DROP ROLE regress_current_logfile;
|
DROP ROLE regress_current_logfile;
|
||||||
|
|
||||||
|
-- pg_column_toast_chunk_id
|
||||||
|
CREATE TABLE test_chunk_id (a TEXT, b TEXT STORAGE EXTERNAL);
|
||||||
|
INSERT INTO test_chunk_id VALUES ('x', repeat('x', 8192));
|
||||||
|
SELECT t.relname AS toastrel FROM pg_class c
|
||||||
|
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
|
||||||
|
WHERE c.relname = 'test_chunk_id'
|
||||||
|
\gset
|
||||||
|
SELECT pg_column_toast_chunk_id(a) IS NULL,
|
||||||
|
pg_column_toast_chunk_id(b) IN (SELECT chunk_id FROM pg_toast.:toastrel)
|
||||||
|
FROM test_chunk_id;
|
||||||
|
DROP TABLE test_chunk_id;
|
||||||
|
|
Loading…
Reference in New Issue