PostgreSQL Source Code git master
test_custom_var_stats.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------------
2 *
3 * test_custom_var_stats.c
4 * Test module for variable-sized custom pgstats
5 *
6 * Copyright (c) 2025, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/test/modules/test_custom_var_stats/test_custom_var_stats.c
10 *
11 * ------------------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "common/hashfn.h"
16#include "funcapi.h"
18#include "utils/builtins.h"
20
22 .name = "test_custom_var_stats",
23 .version = PG_VERSION
24);
25
26#define TEST_CUSTOM_VAR_MAGIC_NUMBER (0xBEEFBEEF)
27
28/*--------------------------------------------------------------------------
29 * Macros and constants
30 *--------------------------------------------------------------------------
31 */
32
33/*
34 * Kind ID for test_custom_var_stats statistics.
35 */
36#define PGSTAT_KIND_TEST_CUSTOM_VAR_STATS 25
37
38/* File paths for auxiliary data serialization */
39#define TEST_CUSTOM_AUX_DATA_DESC "pg_stat/test_custom_var_stats_desc.stats"
40
41/*
42 * Hash statistic name to generate entry index for pgstat lookup.
43 */
44#define PGSTAT_CUSTOM_VAR_STATS_IDX(name) hash_bytes_extended((const unsigned char *) name, strlen(name), 0)
45
46/*--------------------------------------------------------------------------
47 * Type definitions
48 *--------------------------------------------------------------------------
49 */
50
51/* Backend-local pending statistics before flush to shared memory */
53{
54 PgStat_Counter numcalls; /* times statistic was incremented */
56
57/* Shared memory statistics entry visible to all backends */
59{
60 PgStatShared_Common header; /* standard pgstat entry header */
61 PgStat_StatCustomVarEntry stats; /* custom statistics data */
62 dsa_pointer description; /* pointer to description string in DSA */
64
65/*--------------------------------------------------------------------------
66 * Global Variables
67 *--------------------------------------------------------------------------
68 */
69
70/* File handle for auxiliary data serialization */
71static FILE *fd_description = NULL;
72
73/* Current write offset in fd_description file */
75
76/* DSA area for storing variable-length description strings */
78
79/*--------------------------------------------------------------------------
80 * Function prototypes
81 *--------------------------------------------------------------------------
82 */
83
84/* Flush callback: merge pending stats into shared memory */
86 bool nowait);
87
88/* Serialization callback: write auxiliary entry data */
90 const PgStatShared_Common *header,
91 FILE *statfile);
92
93/* Deserialization callback: read auxiliary entry data */
95 const PgStatShared_Common *header,
96 FILE *statfile);
97
98/* Finish callback: end of statistics file operations */
100
101/*--------------------------------------------------------------------------
102 * Custom kind configuration
103 *--------------------------------------------------------------------------
104 */
105
107 .name = "test_custom_var_stats",
108 .fixed_amount = false, /* variable number of entries */
109 .write_to_file = true, /* persist across restarts */
110 .track_entry_count = true, /* count active entries */
111 .accessed_across_databases = true, /* global statistics */
112 .shared_size = sizeof(PgStatShared_CustomVarEntry),
113 .shared_data_off = offsetof(PgStatShared_CustomVarEntry, stats),
114 .shared_data_len = sizeof(((PgStatShared_CustomVarEntry *) 0)->stats),
115 .pending_size = sizeof(PgStat_StatCustomVarEntry),
116 .flush_pending_cb = test_custom_stats_var_flush_pending_cb,
117 .to_serialized_data = test_custom_stats_var_to_serialized_data,
118 .from_serialized_data = test_custom_stats_var_from_serialized_data,
120};
121
122/*--------------------------------------------------------------------------
123 * Module initialization
124 *--------------------------------------------------------------------------
125 */
126
127void
129{
130 /* Must be loaded via shared_preload_libraries */
132 return;
133
134 /* Register custom statistics kind */
136}
137
138/*--------------------------------------------------------------------------
139 * Statistics callback functions
140 *--------------------------------------------------------------------------
141 */
142
143/*
144 * test_custom_stats_var_flush_pending_cb
145 * Merge pending backend statistics into shared memory
146 *
147 * Called by pgstat collector to flush accumulated local statistics
148 * to shared memory where other backends can read them.
149 *
150 * Returns false only if nowait=true and lock acquisition fails.
151 */
152static bool
154{
155 PgStat_StatCustomVarEntry *pending_entry;
156 PgStatShared_CustomVarEntry *shared_entry;
157
158 pending_entry = (PgStat_StatCustomVarEntry *) entry_ref->pending;
159 shared_entry = (PgStatShared_CustomVarEntry *) entry_ref->shared_stats;
160
161 if (!pgstat_lock_entry(entry_ref, nowait))
162 return false;
163
164 /* Add pending counts to shared totals */
165 shared_entry->stats.numcalls += pending_entry->numcalls;
166
167 pgstat_unlock_entry(entry_ref);
168
169 return true;
170}
171
172/*
173 * test_custom_stats_var_to_serialized_data() -
174 *
175 * Serialize auxiliary data (descriptions) for custom statistics entries
176 * to a secondary statistics file. This is called while writing the statistics
177 * to disk.
178 *
179 * This callback writes a mix of data within the main pgstats file and a
180 * secondary statistics file. The following data is written to the main file for
181 * each entry:
182 * - An arbitrary magic number.
183 * - An offset. This is used to know the location we need to look at
184 * to retrieve the information from the second file.
185 *
186 * The following data is written to the secondary statistics file:
187 * - The entry key, cross-checked with the data from the main file
188 * when reloaded.
189 * - The length of the description.
190 * - The description data itself.
191 */
192static void
194 const PgStatShared_Common *header,
195 FILE *statfile)
196{
197 char *description;
198 size_t len;
200 bool found;
202
203 /*
204 * First mark the main file with a magic number, keeping a trace that some
205 * auxiliary data will exist in the secondary statistics file.
206 */
207 pgstat_write_chunk_s(statfile, &magic_number);
208
209 /* Open statistics file for writing. */
210 if (!fd_description)
211 {
213 if (fd_description == NULL)
214 {
215 ereport(LOG,
217 errmsg("could not open statistics file \"%s\" for writing: %m",
219 return;
220 }
221
222 /* Initialize offset for secondary statistics file. */
224 }
225
226 /* Write offset to the main data file */
228
229 /*
230 * First write the entry key to the secondary statistics file. This will
231 * be cross-checked with the key read from main stats file at loading
232 * time.
233 */
236
238 custom_stats_description_dsa = GetNamedDSA("test_custom_stat_dsa", &found);
239
240 /* Handle entries without descriptions */
242 {
243 /* length to description file */
244 len = 0;
246 fd_description_offset += sizeof(size_t);
247 return;
248 }
249
250 /*
251 * Retrieve description from DSA, then write the length followed by the
252 * description.
253 */
255 entry->description);
256 len = strlen(description) + 1;
259
260 /*
261 * Update offset for next entry, counting for the length (size_t) of the
262 * description and the description contents.
263 */
264 fd_description_offset += len + sizeof(size_t);
265}
266
267/*
268 * test_custom_stats_var_from_serialized_data() -
269 *
270 * Read auxiliary data (descriptions) for custom statistics entries from
271 * the secondary statistics file. This is called while loading the statistics
272 * at startup.
273 *
274 * See the top of test_custom_stats_var_to_serialized_data() for a
275 * detailed description of the data layout read here.
276 */
277static bool
279 const PgStatShared_Common *header,
280 FILE *statfile)
281{
283 dsa_pointer dp;
284 size_t len;
285 pgoff_t offset;
286 char *buffer;
287 bool found;
288 uint32 magic_number = 0;
289 PgStat_HashKey file_key;
290
291 /* Check the magic number first, in the main file. */
292 if (!pgstat_read_chunk_s(statfile, &magic_number))
293 {
294 elog(WARNING, "failed to read magic number from statistics file");
295 return false;
296 }
297
298 if (magic_number != TEST_CUSTOM_VAR_MAGIC_NUMBER)
299 {
300 elog(WARNING, "found magic number %u from statistics file, should be %u",
301 magic_number, TEST_CUSTOM_VAR_MAGIC_NUMBER);
302 return false;
303 }
304
305 /*
306 * Read the offset from the main stats file, to be able to read the
307 * auxiliary data from the secondary statistics file.
308 */
309 if (!pgstat_read_chunk_s(statfile, &offset))
310 {
311 elog(WARNING, "failed to read metadata offset from statistics file");
312 return false;
313 }
314
315 /* Open statistics file for reading if not already open */
316 if (!fd_description)
317 {
319 if (fd_description == NULL)
320 {
321 if (errno != ENOENT)
322 ereport(LOG,
324 errmsg("could not open statistics file \"%s\" for reading: %m",
327 return false;
328 }
329 }
330
331 /* Read data from the secondary statistics file, at the specified offset */
332 if (fseeko(fd_description, offset, SEEK_SET) != 0)
333 {
334 elog(WARNING, "could not seek in file \"%s\": %m",
336 return false;
337 }
338
339 /* Read the hash key from the secondary statistics file */
340 if (!pgstat_read_chunk_s(fd_description, &file_key))
341 {
342 elog(WARNING, "failed to read hash key from file");
343 return false;
344 }
345
346 /* Check key consistency */
347 if (file_key.kind != key->kind ||
348 file_key.dboid != key->dboid ||
349 file_key.objid != key->objid)
350 {
351 elog(WARNING, "found entry key %u/%u/%" PRIu64 " not matching with %u/%u/%" PRIu64,
352 file_key.kind, file_key.dboid, file_key.objid,
353 key->kind, key->dboid, key->objid);
354 return false;
355 }
356
357 entry = (PgStatShared_CustomVarEntry *) header;
358
359 /* Read the description length and its data */
361 {
362 elog(WARNING, "failed to read metadata length from statistics file");
363 return false;
364 }
365
366 /* Handle empty descriptions */
367 if (len == 0)
368 {
370 return true;
371 }
372
373 /* Initialize DSA if needed */
375 custom_stats_description_dsa = GetNamedDSA("test_custom_stat_dsa", &found);
376
378 {
379 elog(WARNING, "could not access DSA for custom statistics descriptions");
380 return false;
381 }
382
383 buffer = palloc(len);
384 if (!pgstat_read_chunk(fd_description, buffer, len))
385 {
386 pfree(buffer);
387 elog(WARNING, "failed to read description from file");
388 return false;
389 }
390
391 /* Allocate space in DSA and copy the description */
394 entry->description = dp;
395 pfree(buffer);
396
397 return true;
398}
399
400/*
401 * test_custom_stats_var_finish() -
402 *
403 * Cleanup function called at the end of statistics file operations.
404 * Handles closing files and cleanup based on the operation type.
405 */
406static void
408{
409 switch (status)
410 {
411 case STATS_WRITE:
412 if (!fd_description)
413 return;
414
416
417 /* Check for write errors and cleanup if necessary */
418 if (ferror(fd_description))
419 {
420 ereport(LOG,
422 errmsg("could not write to file \"%s\": %m",
426 }
427 else if (FreeFile(fd_description) < 0)
428 {
429 ereport(LOG,
431 errmsg("could not close file \"%s\": %m",
434 }
435 break;
436
437 case STATS_READ:
438 if (fd_description)
440
441 /* Remove the file after reading */
442 elog(DEBUG2, "removing file \"%s\"", TEST_CUSTOM_AUX_DATA_DESC);
444 break;
445
446 case STATS_DISCARD:
447 {
448 int ret;
449
450 /* Attempt to remove the file */
451 ret = unlink(TEST_CUSTOM_AUX_DATA_DESC);
452 if (ret != 0)
453 {
454 if (errno == ENOENT)
455 elog(LOG,
456 "didn't need to unlink file \"%s\" - didn't exist",
458 else
459 ereport(LOG,
461 errmsg("could not unlink file \"%s\": %m",
463 }
464 else
465 {
466 ereport(LOG,
467 (errmsg_internal("unlinked file \"%s\"",
469 }
470 }
471 break;
472 }
473
474 fd_description = NULL;
475}
476
477/*--------------------------------------------------------------------------
478 * Helper functions
479 *--------------------------------------------------------------------------
480 */
481
482/*
483 * test_custom_stats_var_fetch_entry
484 * Look up custom statistic by name
485 *
486 * Returns statistics entry from shared memory, or NULL if not found.
487 */
490{
491 /* Fetch entry by hashed name */
495 PGSTAT_CUSTOM_VAR_STATS_IDX(stat_name));
496}
497
498/*--------------------------------------------------------------------------
499 * SQL-callable functions
500 *--------------------------------------------------------------------------
501 */
502
503/*
504 * test_custom_stats_var_create
505 * Create new custom statistic entry
506 *
507 * Initializes a statistics entry with the given name and description.
508 */
510Datum
512{
513 PgStat_EntryRef *entry_ref;
514 PgStatShared_CustomVarEntry *shared_entry;
515 char *stat_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
518 bool found;
519
520 /* Validate name length first */
521 if (strlen(stat_name) >= NAMEDATALEN)
523 (errcode(ERRCODE_NAME_TOO_LONG),
524 errmsg("custom statistic name \"%s\" is too long", stat_name),
525 errdetail("Name must be less than %d characters.", NAMEDATALEN)));
526
527 /* Initialize DSA and description provided */
529 custom_stats_description_dsa = GetNamedDSA("test_custom_stat_dsa", &found);
530
533 (errmsg("could not access DSA for custom statistics descriptions")));
534
535 /* Allocate space in DSA and copy description */
539 strlen(description) + 1);
540
541 /* Create or get existing entry */
543 PGSTAT_CUSTOM_VAR_STATS_IDX(stat_name), true);
544
545 if (!entry_ref)
547
548 shared_entry = (PgStatShared_CustomVarEntry *) entry_ref->shared_stats;
549
550 /* Zero-initialize statistics */
551 memset(&shared_entry->stats, 0, sizeof(shared_entry->stats));
552
553 /* Store description pointer */
554 shared_entry->description = dp;
555
556 pgstat_unlock_entry(entry_ref);
557
559}
560
561/*
562 * test_custom_stats_var_update
563 * Increment custom statistic counter
564 *
565 * Increments call count in backend-local memory. Changes are flushed
566 * to shared memory by the statistics collector.
567 */
569Datum
571{
572 char *stat_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
573 PgStat_EntryRef *entry_ref;
574 PgStat_StatCustomVarEntry *pending_entry;
575
576 /* Get pending entry in local memory */
578 PGSTAT_CUSTOM_VAR_STATS_IDX(stat_name), NULL);
579
580 pending_entry = (PgStat_StatCustomVarEntry *) entry_ref->pending;
581 pending_entry->numcalls++;
582
584}
585
586/*
587 * test_custom_stats_var_drop
588 * Remove custom statistic entry
589 *
590 * Drops the named statistic from shared memory.
591 */
593Datum
595{
596 char *stat_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
597
598 /* Drop entry and request GC if the entry could not be freed */
600 PGSTAT_CUSTOM_VAR_STATS_IDX(stat_name)))
602
604}
605
606/*
607 * test_custom_stats_var_report
608 * Retrieve custom statistic values
609 *
610 * Returns single row with statistic name, call count, and description if the
611 * statistic exists, otherwise returns no rows.
612 */
614Datum
616{
617 FuncCallContext *funcctx;
618 char *stat_name;
619 PgStat_StatCustomVarEntry *stat_entry;
620
621 if (SRF_IS_FIRSTCALL())
622 {
623 TupleDesc tupdesc;
624 MemoryContext oldcontext;
625
626 /* Initialize SRF context */
627 funcctx = SRF_FIRSTCALL_INIT();
628 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
629
630 /* Get composite return type */
631 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
632 elog(ERROR, "test_custom_stats_var_report: return type is not composite");
633
634 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
635 funcctx->max_calls = 1; /* single row result */
636
637 MemoryContextSwitchTo(oldcontext);
638 }
639
640 funcctx = SRF_PERCALL_SETUP();
641
642 if (funcctx->call_cntr < funcctx->max_calls)
643 {
644 Datum values[3];
645 bool nulls[3] = {false, false, false};
646 HeapTuple tuple;
647 PgStat_EntryRef *entry_ref;
648 PgStatShared_CustomVarEntry *shared_entry;
649 char *description = NULL;
650 bool found;
651
652 stat_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
653 stat_entry = test_custom_stats_var_fetch_entry(stat_name);
654
655 /* Return row only if entry exists */
656 if (stat_entry)
657 {
658 /* Get entry ref to access shared entry */
660 PGSTAT_CUSTOM_VAR_STATS_IDX(stat_name), false, NULL);
661
662 if (entry_ref)
663 {
664 shared_entry = (PgStatShared_CustomVarEntry *) entry_ref->shared_stats;
665
666 /* Get description from DSA if available */
667 if (DsaPointerIsValid(shared_entry->description))
668 {
670 custom_stats_description_dsa = GetNamedDSA("test_custom_stat_dsa", &found);
671
674 }
675 }
676
677 values[0] = PointerGetDatum(cstring_to_text(stat_name));
678 values[1] = Int64GetDatum(stat_entry->numcalls);
679
680 if (description)
682 else
683 nulls[2] = true;
684
685 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
686 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
687 }
688 }
689
690 SRF_RETURN_DONE(funcctx);
691}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define PG_BINARY_R
Definition: c.h:1252
uint32_t uint32
Definition: c.h:552
#define PG_BINARY_W
Definition: c.h:1253
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:957
uint64 dsa_pointer
Definition: dsa.h:62
#define dsa_allocate(area, size)
Definition: dsa.h:109
#define InvalidDsaPointer
Definition: dsa.h:78
#define DsaPointerIsValid(x)
Definition: dsa.h:106
dsa_area * GetNamedDSA(const char *name, bool *found)
Definition: dsm_registry.c:276
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
int errcode_for_file_access(void)
Definition: elog.c:886
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define LOG
Definition: elog.h:31
#define WARNING
Definition: elog.h:36
#define DEBUG2
Definition: elog.h:29
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2260
int FreeFile(FILE *file)
Definition: fd.c:2823
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2624
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1786
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define NAMEDATALEN
const void size_t len
PgStat_EntryRef * pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *created_entry)
Definition: pgstat.c:1275
void pgstat_reset_of_kind(PgStat_Kind kind)
Definition: pgstat.c:886
bool pgstat_read_chunk(FILE *fpin, void *ptr, size_t len)
Definition: pgstat.c:1763
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat.c:944
void pgstat_register_kind(PgStat_Kind kind, const PgStat_KindInfo *kind_info)
Definition: pgstat.c:1473
void pgstat_write_chunk(FILE *fpout, void *ptr, size_t len)
Definition: pgstat.c:1565
int64 PgStat_Counter
Definition: pgstat.h:67
#define pgstat_write_chunk_s(fpout, ptr)
PgStat_StatsFileOp
@ STATS_WRITE
@ STATS_READ
@ STATS_DISCARD
struct PgStat_HashKey PgStat_HashKey
#define pgstat_read_chunk_s(fpin, ptr)
void pgstat_request_entry_refs_gc(void)
Definition: pgstat_shmem.c:745
PgStat_EntryRef * pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create, bool *created_entry)
Definition: pgstat_shmem.c:469
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:720
bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait)
Definition: pgstat_shmem.c:690
PgStat_EntryRef * pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, uint64 objid, bool nowait)
Definition: pgstat_shmem.c:729
off_t pgoff_t
Definition: port.h:421
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
uint64_t Datum
Definition: postgres.h:70
#define InvalidOid
Definition: postgres_ext.h:37
uint64 max_calls
Definition: funcapi.h:74
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
PgStat_StatCustomVarEntry stats
PgStatShared_Common * shared_stats
PgStat_Kind kind
const char *const name
Definition: dsa.c:348
static dsa_area * custom_stats_description_dsa
static void test_custom_stats_var_to_serialized_data(const PgStat_HashKey *key, const PgStatShared_Common *header, FILE *statfile)
static void test_custom_stats_var_finish(PgStat_StatsFileOp status)
PG_FUNCTION_INFO_V1(test_custom_stats_var_create)
static pgoff_t fd_description_offset
void _PG_init(void)
Datum test_custom_stats_var_update(PG_FUNCTION_ARGS)
struct PgStatShared_CustomVarEntry PgStatShared_CustomVarEntry
Datum test_custom_stats_var_drop(PG_FUNCTION_ARGS)
static const PgStat_KindInfo custom_stats
struct PgStat_StatCustomVarEntry PgStat_StatCustomVarEntry
PG_MODULE_MAGIC_EXT(.name="test_custom_var_stats",.version=PG_VERSION)
Datum test_custom_stats_var_create(PG_FUNCTION_ARGS)
Datum test_custom_stats_var_report(PG_FUNCTION_ARGS)
static bool test_custom_stats_var_flush_pending_cb(PgStat_EntryRef *entry_ref, bool nowait)
#define TEST_CUSTOM_AUX_DATA_DESC
static PgStat_StatCustomVarEntry * test_custom_stats_var_fetch_entry(const char *stat_name)
static bool test_custom_stats_var_from_serialized_data(const PgStat_HashKey *key, const PgStatShared_Common *header, FILE *statfile)
#define PGSTAT_KIND_TEST_CUSTOM_VAR_STATS
#define TEST_CUSTOM_VAR_MAGIC_NUMBER
#define PGSTAT_CUSTOM_VAR_STATS_IDX(name)
static FILE * fd_description
text * cstring_to_text(const char *s)
Definition: varlena.c:181
char * text_to_cstring(const text *t)
Definition: varlena.c:214
const char * description
const char * name
#define fseeko(stream, offset, origin)
Definition: win32_port.h:206