Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit df0f467

Browse files
arseny114Arseny Kositsyn
authored and
Arseny Kositsyn
committedMay 14, 2025
[PGPRO-12159] Added pageinspect functions for rum.
This commit adds three functions for low-level exploration of the index's rum pages: 1) rum_metapage_info() -- is used to examine the information posted on the meta page (flags: {meta}). 2) rum_page_opaque_info() -- is used to examine information that is placed in the opaque area of the index page (any index page). 3) rum_leaf_data_page_items() -- is used to examine the information that is placed on the leaf pages of the posting tree (flags: {leaf, data}). To extract information, all these functions need to pass the index name and the page number. Tags: rum
1 parent cbf80ab commit df0f467

File tree

3 files changed

+709
-1
lines changed

3 files changed

+709
-1
lines changed
 

‎Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ OBJS = src/rumsort.o src/rum_ts_utils.o src/rumtsquery.o \
99
src/rumbtree.o src/rumbulk.o src/rumdatapage.o \
1010
src/rumentrypage.o src/rumget.o src/ruminsert.o \
1111
src/rumscan.o src/rumutil.o src/rumvacuum.o src/rumvalidate.o \
12-
src/btree_rum.o src/rum_arr_utils.o $(WIN32RES)
12+
src/btree_rum.o src/rum_arr_utils.o src/rum_debug_funcs.o $(WIN32RES)
1313

1414
DATA_updates = rum--1.0--1.1.sql rum--1.1--1.2.sql \
1515
rum--1.2--1.3.sql

‎rum_init.sql

+38
Original file line numberDiff line numberDiff line change
@@ -1724,3 +1724,41 @@ RETURNS float4
17241724
AS 'MODULE_PATHNAME', 'rum_ts_score_td'
17251725
LANGUAGE C IMMUTABLE STRICT;
17261726

1727+
/*--------------------RUM debug functions-----------------------*/
1728+
1729+
CREATE FUNCTION rum_metapage_info(
1730+
IN rel_name text,
1731+
IN blk_num int8,
1732+
OUT pending_head bigint,
1733+
OUT pending_tail bigint,
1734+
OUT tail_free_size int4,
1735+
OUT n_pending_pages bigint,
1736+
OUT n_pending_tuples bigint,
1737+
OUT n_total_pages bigint,
1738+
OUT n_entry_pages bigint,
1739+
OUT n_data_pages bigint,
1740+
OUT n_entries bigint,
1741+
OUT version bigint)
1742+
AS 'MODULE_PATHNAME', 'rum_metapage_info'
1743+
LANGUAGE C STRICT PARALLEL SAFE;
1744+
1745+
CREATE FUNCTION rum_page_opaque_info(
1746+
IN rel_name text,
1747+
IN blk_num int8,
1748+
OUT leftlink bigint,
1749+
OUT rightlink bigint,
1750+
OUT maxoff int4,
1751+
OUT freespace int4,
1752+
OUT flags text[])
1753+
AS 'MODULE_PATHNAME', 'rum_page_opaque_info'
1754+
LANGUAGE C STRICT PARALLEL SAFE;
1755+
1756+
CREATE FUNCTION rum_leaf_data_page_items(
1757+
IN rel_name text,
1758+
IN blk_num int8,
1759+
OUT tuple_id tid,
1760+
OUT add_info_is_null bool,
1761+
OUT addInfo varchar)
1762+
RETURNS SETOF record
1763+
AS 'MODULE_PATHNAME', 'rum_leaf_data_page_items'
1764+
LANGUAGE C STRICT PARALLEL SAFE;

‎src/rum_debug_funcs.c

+670
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,670 @@
1+
/*
2+
* rum_debug_funcs.c
3+
* Functions to investigate the content of RUM indexes
4+
*
5+
* Copyright (c) 2025, Postgres Professional
6+
*
7+
* IDENTIFICATION
8+
* contrib/rum/rum_debug_funcs.c
9+
*
10+
* LIST OF ISSUES:
11+
* 1) Strangely, the index version is returned in the
12+
* rum_metapage_info() function.
13+
*
14+
* 2) Using obsolete macros in the addInfoGetText() function.
15+
*
16+
* 3) I/O functions were not available for all types in
17+
* in the addInfoGetText() function.
18+
*
19+
* 4) The unclear logic of choosing the attribute number
20+
* that the addInfo corresponds to.
21+
*/
22+
23+
#include "postgres.h"
24+
#include "fmgr.h"
25+
#include "funcapi.h"
26+
#include "catalog/namespace.h"
27+
#include "utils/array.h"
28+
#include "utils/builtins.h"
29+
#include "utils/fmgroids.h"
30+
#include "access/relation.h"
31+
#include "utils/varlena.h"
32+
#include "rum.h"
33+
34+
PG_FUNCTION_INFO_V1(rum_metapage_info);
35+
PG_FUNCTION_INFO_V1(rum_page_opaque_info);
36+
PG_FUNCTION_INFO_V1(rum_leaf_data_page_items);
37+
38+
static Page get_page_from_raw(bytea *raw_page);
39+
static Datum addInfoGetText(Datum addInfo, Oid atttypid);
40+
static Relation get_rel_from_name(text *relname);
41+
static bytea *get_rel_raw_page(Relation rel, BlockNumber blkno);
42+
43+
/*
44+
* The rum_metapage_info() function is used to retrieve
45+
* information stored on the meta page of the rum index.
46+
* To scan, need the index name and the page number.
47+
* (for the meta page blkno = 0).
48+
*/
49+
Datum
50+
rum_metapage_info(PG_FUNCTION_ARGS)
51+
{
52+
/* Reading input arguments */
53+
text *relname = PG_GETARG_TEXT_PP(0);
54+
uint32 blkno = PG_GETARG_UINT32(1);
55+
56+
Relation rel; /* needed to initialize the RumState
57+
structure */
58+
59+
bytea *raw_page; /* the raw page obtained from rel */
60+
RumPageOpaque opaq; /* data from the opaque area of the page */
61+
RumMetaPageData *metadata; /* data stored on the meta page */
62+
Page page; /* the page to be scanned */
63+
64+
TupleDesc tupdesc; /* description of the result tuple */
65+
HeapTuple resultTuple; /* for the results */
66+
Datum values[10]; /* return values */
67+
bool nulls[10]; /* true if the corresponding value is NULL */
68+
69+
/* Only the superuser can use this */
70+
if (!superuser())
71+
ereport(ERROR,
72+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
73+
errmsg("must be superuser to use raw page functions")));
74+
75+
/* Getting rel by name and raw page by number */
76+
rel = get_rel_from_name(relname);
77+
raw_page = get_rel_raw_page(rel, blkno);
78+
relation_close(rel, AccessShareLock);
79+
80+
/* Getting a copy of the page from the raw page */
81+
page = get_page_from_raw(raw_page);
82+
83+
/* If the page is new, the function should return NULL */
84+
if (PageIsNew(page))
85+
PG_RETURN_NULL();
86+
87+
/* Checking the size of the opaque area of the page */
88+
if (PageGetSpecialSize(page) != MAXALIGN(sizeof(RumPageOpaqueData)))
89+
ereport(ERROR,
90+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
91+
errmsg("input page is not a valid RUM metapage"),
92+
errdetail("Expected special size %d, got %d.",
93+
(int) MAXALIGN(sizeof(RumPageOpaqueData)),
94+
(int) PageGetSpecialSize(page))));
95+
96+
/* Getting a page description from an opaque area */
97+
opaq = RumPageGetOpaque(page);
98+
99+
/* Checking the flags */
100+
if (opaq->flags != RUM_META)
101+
ereport(ERROR,
102+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
103+
errmsg("input page is not a RUM metapage"),
104+
errdetail("Flags %04X, expected %04X",
105+
opaq->flags, RUM_META)));
106+
107+
/* Build a tuple descriptor for our result type */
108+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
109+
elog(ERROR, "return type must be a row type");
110+
111+
/* Getting information from the meta page */
112+
metadata = RumPageGetMeta(page);
113+
114+
memset(nulls, 0, sizeof(nulls));
115+
116+
/*
117+
* Writing data from metadata to values.
118+
*
119+
* The first five values are obsolete because the
120+
* pending list was removed from the rum index.
121+
*/
122+
values[0] = Int64GetDatum(metadata->head);
123+
values[1] = Int64GetDatum(metadata->tail);
124+
values[2] = Int32GetDatum(metadata->tailFreeSize);
125+
values[3] = Int64GetDatum(metadata->nPendingPages);
126+
values[4] = Int64GetDatum(metadata->nPendingHeapTuples);
127+
values[5] = Int64GetDatum(metadata->nTotalPages);
128+
values[6] = Int64GetDatum(metadata->nEntryPages);
129+
values[7] = Int64GetDatum(metadata->nDataPages);
130+
values[8] = Int64GetDatum(metadata->nEntries);
131+
values[9] = Int64GetDatum(metadata->rumVersion);
132+
133+
/* Build and return the result tuple */
134+
resultTuple = heap_form_tuple(tupdesc, values, nulls);
135+
136+
/* Returning the result */
137+
return HeapTupleGetDatum(resultTuple);
138+
}
139+
140+
/*
141+
* The rum_page_opaque_info() function is used to retrieve
142+
* information stored in the opaque area of the index rum
143+
* page. To scan, need the index name and the page number.
144+
*/
145+
Datum
146+
rum_page_opaque_info(PG_FUNCTION_ARGS)
147+
{
148+
/* Reading input arguments */
149+
text *relname = PG_GETARG_TEXT_PP(0);
150+
uint32 blkno = PG_GETARG_UINT32(1);
151+
152+
Relation rel; /* needed to initialize the RumState
153+
structure */
154+
155+
bytea *raw_page; /* the raw page obtained from rel */
156+
RumPageOpaque opaq; /* data from the opaque area of the page */
157+
Page page; /* the page to be scanned */
158+
159+
HeapTuple resultTuple; /* for the results */
160+
TupleDesc tupdesc; /* description of the result tuple */
161+
162+
Datum values[5]; /* return values */
163+
bool nulls[5]; /* true if the corresponding value is NULL */
164+
Datum flags[16]; /* array with flags in text format */
165+
int nflags = 0; /* index in the array of flags */
166+
uint16 flagbits; /* flags in the opaque area of the page */
167+
168+
/* Only the superuser can use this */
169+
if (!superuser())
170+
ereport(ERROR,
171+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
172+
errmsg("must be superuser to use raw page functions")));
173+
174+
/* Getting rel by name and raw page by number */
175+
rel = get_rel_from_name(relname);
176+
raw_page = get_rel_raw_page(rel, blkno);
177+
relation_close(rel, AccessShareLock);
178+
179+
/* Getting a copy of the page from the raw page */
180+
page = get_page_from_raw(raw_page);
181+
182+
/* If the page is new, the function should return NULL */
183+
if (PageIsNew(page))
184+
PG_RETURN_NULL();
185+
186+
/* Checking the size of the opaque area of the page */
187+
if (PageGetSpecialSize(page) != MAXALIGN(sizeof(RumPageOpaqueData)))
188+
ereport(ERROR,
189+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
190+
errmsg("input page is not a valid RUM data leaf page"),
191+
errdetail("Expected special size %d, got %d.",
192+
(int) MAXALIGN(sizeof(RumPageOpaqueData)),
193+
(int) PageGetSpecialSize(page))));
194+
195+
/* Getting a page description from an opaque area */
196+
opaq = RumPageGetOpaque(page);
197+
198+
/* Build a tuple descriptor for our result type */
199+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
200+
elog(ERROR, "return type must be a row type");
201+
202+
/* Convert the flags bitmask to an array of human-readable names */
203+
flagbits = opaq->flags;
204+
if (flagbits & RUM_DATA)
205+
flags[nflags++] = CStringGetTextDatum("data");
206+
if (flagbits & RUM_LEAF)
207+
flags[nflags++] = CStringGetTextDatum("leaf");
208+
if (flagbits & RUM_DELETED)
209+
flags[nflags++] = CStringGetTextDatum("deleted");
210+
if (flagbits & RUM_META)
211+
flags[nflags++] = CStringGetTextDatum("meta");
212+
if (flagbits & RUM_LIST)
213+
flags[nflags++] = CStringGetTextDatum("list");
214+
if (flagbits & RUM_LIST_FULLROW)
215+
flags[nflags++] = CStringGetTextDatum("list_fullrow");
216+
flagbits &= ~(RUM_DATA | RUM_LEAF | RUM_DELETED | RUM_META | RUM_LIST |
217+
RUM_LIST_FULLROW);
218+
if (flagbits)
219+
{
220+
/* any flags we don't recognize are printed in hex */
221+
flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits));
222+
}
223+
224+
memset(nulls, 0, sizeof(nulls));
225+
226+
/*
227+
* Writing data from metadata to values.
228+
*/
229+
values[0] = Int64GetDatum(opaq->leftlink);
230+
values[1] = Int64GetDatum(opaq->rightlink);
231+
values[2] = Int32GetDatum(opaq->maxoff);
232+
values[3] = Int32GetDatum(opaq->freespace);
233+
values[4] = PointerGetDatum(construct_array_builtin(flags, nflags, TEXTOID));
234+
235+
/* Build and return the result tuple. */
236+
resultTuple = heap_form_tuple(tupdesc, values, nulls);
237+
238+
/* Returning the result */
239+
return HeapTupleGetDatum(resultTuple);
240+
}
241+
242+
/*
243+
* A structure that stores information between calls to the
244+
* rum_leaf_data_page_items() function. This information is
245+
* necessary to scan the page.
246+
*/
247+
typedef struct rum_leafpage_items_state
248+
{
249+
/* Number of RumItem structures per {leaf, data} page */
250+
int maxoff;
251+
252+
/* Pointer to the current RumItem */
253+
Pointer item_ptr;
254+
255+
/* A pointer to the RumState structure, which is needed to scan the page */
256+
RumState *rum_state_ptr;
257+
258+
/* A pointer to the description of the attribute, which is addInfo */
259+
Form_pg_attribute addInfo_att_ptr;
260+
} rum_leafpage_items_state;
261+
262+
/*
263+
* The function rum_leaf_data_page_items() is designed to read
264+
* information from the {leaf, data} pages of the rum index.
265+
* The pages scanned by this function are the pages of the
266+
* Posting Tree. The information on the page is stored in RumItem
267+
* structures. The function returns tuple_id, add_info_is_null,
268+
* addinfo. To scan, need the index name and the page number.
269+
* It is an SRF function, i.e. it returns one value per call.
270+
*/
271+
Datum
272+
rum_leaf_data_page_items(PG_FUNCTION_ARGS)
273+
{
274+
/* Reading input arguments */
275+
text *relname = PG_GETARG_TEXT_PP(0);
276+
uint32 blkno = PG_GETARG_UINT32(1);
277+
278+
/*
279+
* The context of the function calls and the pointer
280+
* to the long-lived inter_call_data structure
281+
*/
282+
FuncCallContext *fctx;
283+
rum_leafpage_items_state *inter_call_data;
284+
285+
/* Only the superuser can use this */
286+
if (!superuser())
287+
ereport(ERROR,
288+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
289+
errmsg("must be superuser to use this function")));
290+
291+
/*
292+
* In the case of the first function call, it is necessary
293+
* to get the page by its number and create a Runstate
294+
* structure for scanning the page.
295+
*/
296+
if (SRF_IS_FIRSTCALL())
297+
{
298+
299+
Relation rel; /* needed to initialize the RumState
300+
structure */
301+
bytea *raw_page; /* The raw page obtained from rel */
302+
303+
TupleDesc tupdesc; /* description of the result tuple */
304+
MemoryContext oldmctx; /* the old function memory context */
305+
Page page; /* the page to be scanned */
306+
RumPageOpaque opaq; /* data from the opaque area of the page */
307+
308+
/*
309+
* Initializing the FuncCallContext structure and switching the memory
310+
* context to the one needed for structures that must be saved during
311+
* multiple calls
312+
*/
313+
fctx = SRF_FIRSTCALL_INIT();
314+
oldmctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
315+
316+
/* Getting rel by name and raw page by number */
317+
rel = get_rel_from_name(relname);
318+
raw_page = get_rel_raw_page(rel, blkno);
319+
320+
/* Allocating memory for a long-lived structure */
321+
inter_call_data = palloc(sizeof(rum_leafpage_items_state));
322+
323+
/* Initializing the RumState structure */
324+
inter_call_data->rum_state_ptr = palloc(sizeof(RumState));
325+
initRumState(inter_call_data->rum_state_ptr, rel);
326+
327+
/*
328+
* It is convenient to save a pointer to an attribute
329+
* of addInfo in a long-lived structure for shorter
330+
* access in the future.
331+
*/
332+
inter_call_data->addInfo_att_ptr = inter_call_data->rum_state_ptr->
333+
addAttrs[inter_call_data->rum_state_ptr->attrnAddToColumn - 1];
334+
335+
relation_close(rel, AccessShareLock);
336+
337+
/* Getting a copy of the page from the raw page */
338+
page = get_page_from_raw(raw_page);
339+
340+
/* If the page is new, the function should return NULL */
341+
if (PageIsNew(page))
342+
{
343+
MemoryContextSwitchTo(oldmctx);
344+
PG_RETURN_NULL();
345+
}
346+
347+
/* Checking the size of the opaque area of the page */
348+
if (PageGetSpecialSize(page) != MAXALIGN(sizeof(RumPageOpaqueData)))
349+
ereport(ERROR,
350+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
351+
errmsg("input page is not a valid RUM page"),
352+
errdetail("Expected special size %d, got %d.",
353+
(int) MAXALIGN(sizeof(RumPageOpaqueData)),
354+
(int) PageGetSpecialSize(page))));
355+
356+
/* Getting a page description from an opaque area */
357+
opaq = RumPageGetOpaque(page);
358+
359+
/* Checking the flags */
360+
if (opaq->flags != (RUM_DATA | RUM_LEAF))
361+
ereport(ERROR,
362+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
363+
errmsg("input page is not a RUM {data, leaf} page"),
364+
errdetail("Flags %04X, expected %04X",
365+
opaq->flags, (RUM_DATA | RUM_LEAF))));
366+
367+
/* Build a tuple descriptor for our result type */
368+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
369+
elog(ERROR, "return type must be a row type");
370+
371+
/* Needed to for subsequent recording tupledesc in fctx */
372+
BlessTupleDesc(tupdesc);
373+
374+
/*
375+
* Write to the long-lived structure the number of RumItem
376+
* structures on the page and a pointer to the data on the page.
377+
*/
378+
inter_call_data->maxoff = opaq->maxoff;
379+
inter_call_data->item_ptr = RumDataPageGetData(page);
380+
381+
/*
382+
* Save a pointer to a long-lived structure and
383+
* tuple descriptor for our result type in fctx.
384+
*/
385+
fctx->user_fctx = inter_call_data;
386+
fctx->tuple_desc = tupdesc;
387+
388+
/* Switching to the old memory context */
389+
MemoryContextSwitchTo(oldmctx);
390+
}
391+
392+
/* Preparing to use the FuncCallContext */
393+
fctx = SRF_PERCALL_SETUP();
394+
395+
/* In the current call, we are reading data from the previous one */
396+
inter_call_data = fctx->user_fctx;
397+
398+
/* Go through the page */
399+
if((fctx->call_cntr + 1) <= inter_call_data->maxoff)
400+
{
401+
RumItem rum_item; /* to read data from a page */
402+
Datum values[3]; /* return values */
403+
bool nulls[3]; /* true if the corresponding value is NULL */
404+
405+
/* For the results */
406+
HeapTuple resultTuple;
407+
Datum result;
408+
409+
memset(nulls, 0, sizeof(nulls));
410+
411+
/* Reading information from the page in rum_item */
412+
inter_call_data->item_ptr = rumDataPageLeafRead(inter_call_data->item_ptr,
413+
inter_call_data->rum_state_ptr->attrnAddToColumn,
414+
&rum_item, false, inter_call_data->rum_state_ptr);
415+
416+
/* Writing data from rum_item to values */
417+
values[0] = ItemPointerGetDatum(&(rum_item.iptr));
418+
values[1] = BoolGetDatum(rum_item.addInfoIsNull);
419+
420+
/*
421+
* If addInfo is not NULL, you need to return it as text.
422+
* If addInfo is NULL, then you need to specify this in
423+
* the corresponding value of the nulls array.
424+
*
425+
* You don't have to worry about freeing up memory in the
426+
* addInfoGetText() function, because the memory context
427+
* in which the current SRF function is called is temporary
428+
* and it will be cleaned up between calls.
429+
*/
430+
if(!rum_item.addInfoIsNull)
431+
values[2] = addInfoGetText(rum_item.addInfo,
432+
inter_call_data->addInfo_att_ptr->atttypid);
433+
else nulls[2] = true;
434+
435+
/* Forming the returned tuple */
436+
resultTuple = heap_form_tuple(fctx->tuple_desc, values, nulls);
437+
result = HeapTupleGetDatum(resultTuple);
438+
439+
/* Returning the result of the current call */
440+
SRF_RETURN_NEXT(fctx, result);
441+
}
442+
443+
/* Completing the function */
444+
SRF_RETURN_DONE(fctx);
445+
}
446+
447+
/*
448+
* A copy of the get_page_from_raw()
449+
* function from pageinspect.
450+
*
451+
* Get a palloc'd, maxalign'ed page image
452+
* from the result of get_rel_raw_page()
453+
*/
454+
static Page
455+
get_page_from_raw(bytea *raw_page)
456+
{
457+
Page page;
458+
int raw_page_size;
459+
460+
raw_page_size = VARSIZE_ANY_EXHDR(raw_page);
461+
462+
if (raw_page_size != BLCKSZ)
463+
ereport(ERROR,
464+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
465+
errmsg("invalid page size"),
466+
errdetail("Expected %d bytes, got %d.",
467+
BLCKSZ, raw_page_size)));
468+
469+
page = palloc(raw_page_size);
470+
471+
memcpy(page, VARDATA_ANY(raw_page), raw_page_size);
472+
473+
return page;
474+
}
475+
476+
/*
477+
* An auxiliary function that is used to convert additional
478+
* information into text. This is a universal way to return any type.
479+
*
480+
* The following types of data are checked:
481+
* int2, int4, int8, float4, float8, money, oid, timestamp,
482+
* timestamptz, time, timetz, date, interval, macaddr, inet,
483+
* cidr, text, varchar, char, bytea, bit, varbit, numeric.
484+
*
485+
* All types accepted by rum must be checked, but
486+
* perhaps some types are missing or some are superfluous.
487+
*/
488+
static Datum
489+
addInfoGetText(Datum addInfo, Oid atttypid)
490+
{
491+
char *str_addInfo = NULL;
492+
493+
/* addInfo cannot be NULL */
494+
Assert(DatumGetPointer(addInfo) != NULL);
495+
496+
/*
497+
* Form a string depending on the type of addInfo.
498+
*
499+
* FIXME The macros used below are taken from the pg_type_d file.h,
500+
* and it says not to use them in the new code, then it's not
501+
* clear how to determine the attribute type. In addition, it
502+
* was not possible to find conversion functions for several
503+
* types below.
504+
*/
505+
switch (atttypid)
506+
{
507+
case INT2OID:
508+
str_addInfo = OidOutputFunctionCall(F_INT2OUT, addInfo);
509+
break;
510+
511+
case INT4OID:
512+
str_addInfo = OidOutputFunctionCall(F_INT4OUT, addInfo);
513+
break;
514+
515+
case INT8OID:
516+
str_addInfo = OidOutputFunctionCall(F_INT8OUT, addInfo);
517+
break;
518+
519+
case FLOAT4OID:
520+
str_addInfo = OidOutputFunctionCall(F_FLOAT4OUT, addInfo);
521+
break;
522+
523+
case FLOAT8OID:
524+
str_addInfo = OidOutputFunctionCall(F_FLOAT8OUT, addInfo);
525+
break;
526+
527+
/*case MONEYOID:*/
528+
/* str_addInfo = OidOutputFunctionCall(, addInfo);*/
529+
/* break;*/
530+
531+
case OIDOID:
532+
str_addInfo = OidOutputFunctionCall(F_OIDOUT, addInfo);
533+
break;
534+
535+
case TIMESTAMPOID:
536+
str_addInfo = OidOutputFunctionCall(F_TIMESTAMP_OUT, addInfo);
537+
break;
538+
539+
case TIMESTAMPTZOID:
540+
str_addInfo = OidOutputFunctionCall(F_TIMESTAMPTZ_OUT, addInfo);
541+
break;
542+
543+
case TIMEOID:
544+
str_addInfo = OidOutputFunctionCall(F_TIME_OUT, addInfo);
545+
break;
546+
547+
case TIMETZOID:
548+
str_addInfo = OidOutputFunctionCall(F_TIMETZ_OUT, addInfo);
549+
break;
550+
551+
case DATEOID:
552+
str_addInfo = OidOutputFunctionCall(F_DATE_OUT, addInfo);
553+
break;
554+
555+
case INTERVALOID:
556+
str_addInfo = OidOutputFunctionCall(F_INTERVAL_OUT, addInfo);
557+
break;
558+
559+
case MACADDROID:
560+
str_addInfo = OidOutputFunctionCall(F_MACADDR_OUT, addInfo);
561+
break;
562+
563+
case INETOID:
564+
str_addInfo = OidOutputFunctionCall(F_INET_OUT, addInfo);
565+
break;
566+
567+
case CIDROID:
568+
str_addInfo = OidOutputFunctionCall(F_CIDR_OUT, addInfo);
569+
break;
570+
571+
case TEXTOID:
572+
str_addInfo = OidOutputFunctionCall(F_CIDR_OUT, addInfo);
573+
break;
574+
575+
/*case VARCHAROID:*/
576+
/* str_addInfo = OidOutputFunctionCall(, addInfo);*/
577+
/* break;*/
578+
/**/
579+
/*case CHAROID:*/
580+
/* str_addInfo = OidOutputFunctionCall(, addInfo);*/
581+
/* break;*/
582+
/**/
583+
/*case BYTEAOID:*/
584+
/* str_addInfo = OidOutputFunctionCall(, addInfo);*/
585+
/* break;*/
586+
587+
case BITOID:
588+
str_addInfo = OidOutputFunctionCall(F_BIT_OUT, addInfo);
589+
break;
590+
591+
case VARBITOID:
592+
str_addInfo = OidOutputFunctionCall(F_VARBIT_OUT, addInfo);
593+
break;
594+
595+
case NUMERICOID:
596+
str_addInfo = OidOutputFunctionCall(F_NUMERIC_OUT, addInfo);
597+
break;
598+
}
599+
600+
return CStringGetTextDatum(str_addInfo);
601+
}
602+
603+
/*
604+
* This function and get_rel_raw_page() are derived from the separation
605+
* of the get_raw_page_internal() function, which was copied from the pageinspect code.
606+
* It is needed in order to call the initRumState() function if necessary.
607+
*/
608+
static Relation
609+
get_rel_from_name(text *relname)
610+
{
611+
RangeVar *relrv;
612+
Relation rel;
613+
614+
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
615+
rel = relation_openrv(relrv, AccessShareLock);
616+
617+
if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
618+
ereport(ERROR,
619+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
620+
errmsg("cannot get raw page from relation \"%s\"",
621+
RelationGetRelationName(rel)),
622+
errdetail_relkind_not_supported(rel->rd_rel->relkind)));
623+
624+
/*
625+
* Reject attempts to read non-local temporary relations; we would be
626+
* likely to get wrong data since we have no visibility into the owning
627+
* session's local buffers.
628+
*/
629+
if (RELATION_IS_OTHER_TEMP(rel))
630+
ereport(ERROR,
631+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
632+
errmsg("cannot access temporary tables of other sessions")));
633+
634+
return rel;
635+
}
636+
637+
/*
638+
* This function and get_rel_from_name() are derived from the separation
639+
* of the get_raw_page_internal() function, which was copied from the pageinspect code.
640+
* It is needed in order to call the initRumState() function if necessary.
641+
*/
642+
static bytea *
643+
get_rel_raw_page(Relation rel, BlockNumber blkno)
644+
{
645+
bytea *raw_page;
646+
char *raw_page_data;
647+
Buffer buf;
648+
649+
if (blkno >= RelationGetNumberOfBlocksInFork(rel, MAIN_FORKNUM))
650+
ereport(ERROR,
651+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
652+
errmsg("block number %u is out of range for relation \"%s\"",
653+
blkno, RelationGetRelationName(rel))));
654+
655+
/* Initialize buffer to copy to */
656+
raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
657+
SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
658+
raw_page_data = VARDATA(raw_page);
659+
660+
/* Take a verbatim copy of the page */
661+
buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, NULL);
662+
LockBuffer(buf, BUFFER_LOCK_SHARE);
663+
664+
memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
665+
666+
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
667+
ReleaseBuffer(buf);
668+
669+
return raw_page;
670+
}

0 commit comments

Comments
 (0)
Please sign in to comment.