GCC Code Coverage Report


Directory: src/
File: src/standalone/pg_compat.h
Date: 2026-09-30 11:11:31
Exec Total Coverage
Lines: 36 36 100.0%
Functions: 10 10 100.0%
Branches: 2 2 100.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2026 Tiger Data, Inc.
3 * Licensed under the PostgreSQL License. See LICENSE for details.
4 *
5 * pg_compat.h - Standalone definitions for PostgreSQL page types
6 *
7 * Provides binary-compatible definitions of BlockNumber, ItemPointerData,
8 * PageHeaderData, and page functions for standalone builds. In PG builds,
9 * the real PostgreSQL headers are used instead.
10 *
11 * This enables centroid page code to compile and test without PostgreSQL
12 * while producing pages with identical binary layout.
13 */
14
15 #ifndef VS_PG_COMPAT_H
16 #define VS_PG_COMPAT_H
17
18 /* Only for standalone builds — PG builds use real headers */
19 #ifdef VS_STANDALONE
20
21 #include <assert.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 /*
26 * PostgreSQL's Assert() in standalone builds. Maps to the C library assert,
27 * which is likewise compiled out when NDEBUG is defined, so shared code can
28 * use Assert() under either back-end.
29 */
30 #ifndef Assert
31 #define Assert(condition) assert(condition)
32 #endif
33
34 typedef uintptr_t Datum;
35
36 /* Opaque DSM segment; unused in standalone (threads share the heap). */
37 typedef struct dsm_segment dsm_segment;
38 typedef char *Pointer;
39
40 #define PointerGetDatum(p) ((Datum)(p))
41 #define DatumGetPointer(d) ((Pointer)(d))
42
43 typedef uint32_t BlockNumber;
44 typedef uint16_t OffsetNumber;
45 typedef uint16_t LocationIndex;
46 typedef char *Page;
47
48 #define InvalidBlockNumber ((BlockNumber)0xFFFFFFFF)
49 #define InvalidOffsetNumber ((OffsetNumber)0)
50 #define BLCKSZ 8192
51
52 /* Alignment macros matching PostgreSQL (8-byte on 64-bit) */
53 #define MAXALIGN(len) (((uintptr_t)(len) + 7) & ~(uintptr_t)7)
54
55 /* Single-palloc ceiling, as in PG's memutils.h (vs_alloc maps to malloc in
56 * standalone, but the shared build code sizes against one limit). */
57 #define MaxAllocSize ((size_t)0x3fffffff)
58
59 /* Page layout version — matches PostgreSQL 8.3+ */
60 #define PG_PAGE_LAYOUT_VERSION 4
61
62 /*
63 * PageHeaderData — binary-compatible with PostgreSQL's PageHeaderData
64 * (24 bytes). We use pd_lower/pd_upper/pd_special to track page regions.
65 */
66 typedef struct PageHeaderData
67 {
68 uint64_t pd_lsn; /* 8B - WAL LSN (unused standalone) */
69 uint16_t pd_checksum; /* 2B */
70 uint16_t pd_flags; /* 2B */
71 LocationIndex pd_lower; /* 2B - end of forward-growing region */
72 LocationIndex pd_upper; /* 2B - start of backward-growing region */
73 LocationIndex pd_special; /* 2B - start of special/opaque area */
74 uint16_t pd_pagesize_version; /* 2B - page size | version */
75 uint32_t pd_prune_xid; /* 4B - (unused standalone) */
76 } PageHeaderData;
77
78 typedef PageHeaderData *PageHeader;
79
80 #define SizeOfPageHeaderData (sizeof(PageHeaderData))
81
82 /*
83 * PageGetContents — returns pointer to page content area.
84 * For pages without line pointers, content starts after the header.
85 */
86 static inline char *
87 15684962 PageGetContents(Page page)
88 {
89 15684962 return (char *)page + MAXALIGN(SizeOfPageHeaderData);
90 }
91
92 /*
93 * PageGetSpecialPointer — returns pointer to special (opaque) area.
94 * Matches PostgreSQL's PageGetSpecialPointer macro.
95 */
96 #define PageGetSpecialPointer(page) ((page) + ((PageHeader)(page))->pd_special)
97
98 /*
99 * PageIsNew — true if page has not been initialized by PageInit.
100 */
101 static inline bool
102 784 PageIsNew(const Page page)
103 {
104 784 return ((const PageHeaderData *)page)->pd_upper == 0;
105 }
106
107 /*
108 * PageGetPageSize — extract page size from pd_pagesize_version.
109 */
110 static inline uint16_t
111 784 PageGetPageSize(const Page page)
112 {
113 784 return ((const PageHeaderData *)page)->pd_pagesize_version &
114 (uint16_t)0xFF00;
115 }
116
117 /*
118 * PageGetSpecialSize — size of the special (opaque) area, as PageInit
119 * reserved it (MAXALIGN'd). Matches PostgreSQL's PageGetSpecialSize.
120 */
121 static inline uint16_t
122 784 PageGetSpecialSize(const Page page)
123 {
124 784 return (uint16_t)(PageGetPageSize(page) -
125 784 ((const PageHeaderData *)page)->pd_special);
126 }
127
128 /*
129 * PageInit — initialize a page with standard PG header layout.
130 *
131 * Matches PostgreSQL's PageInit: zeroes the page, sets pd_lower to
132 * the end of the header, pd_upper and pd_special to pageSize minus
133 * MAXALIGN'd special size, and packs size+version.
134 */
135 static inline void
136 4866 PageInit(Page page, uint16_t pageSize, uint16_t specialSize)
137 {
138 4866 PageHeader header = (PageHeader)page;
139
140 4866 specialSize = (uint16_t)MAXALIGN(specialSize);
141
142 4866 memset(page, 0, pageSize);
143
144 4866 header->pd_lower = SizeOfPageHeaderData;
145 4866 header->pd_upper = pageSize - specialSize;
146 4866 header->pd_special = pageSize - specialSize;
147 4866 header->pd_pagesize_version = (pageSize & 0xFF00) | PG_PAGE_LAYOUT_VERSION;
148 4866 }
149
150 /*
151 * ItemPointerData — 6-byte heap TID, binary-compatible with PG.
152 * BlockIdData is two uint16 (high/low halves of BlockNumber).
153 */
154 typedef struct BlockIdData
155 {
156 uint16_t bi_hi;
157 uint16_t bi_lo;
158 } BlockIdData;
159
160 typedef struct ItemPointerData
161 {
162 BlockIdData ip_blkid;
163 OffsetNumber ip_posid;
164 } __attribute__((packed, aligned(2))) ItemPointerData;
165
166 typedef ItemPointerData *ItemPointer;
167
168 static inline BlockNumber
169 726914 ItemPointerGetBlockNumber(const ItemPointerData *tip)
170 {
171 1453828 return ((BlockNumber)tip->ip_blkid.bi_hi << 16) |
172 726914 (BlockNumber)tip->ip_blkid.bi_lo;
173 }
174
175 static inline OffsetNumber
176 576644 ItemPointerGetOffsetNumber(const ItemPointerData *tip)
177 {
178 576644 return tip->ip_posid;
179 }
180
181 static inline void
182 13443536 ItemPointerSet(ItemPointerData *tip, BlockNumber blk, OffsetNumber off)
183 {
184 13443536 tip->ip_blkid.bi_hi = (uint16_t)(blk >> 16);
185 13443536 tip->ip_blkid.bi_lo = (uint16_t)blk;
186 13443536 tip->ip_posid = off;
187 13443536 }
188
189 static inline void
190 ItemPointerSetInvalid(ItemPointerData *tip)
191 {
192 tip->ip_blkid.bi_hi = 0xFFFF;
193 tip->ip_blkid.bi_lo = 0xFFFF;
194 tip->ip_posid = InvalidOffsetNumber;
195 }
196
197 /*
198 * Types/macros the shared parallel build (parallel_build.h) expects from
199 * PostgreSQL's postgres.h / utils/rel.h.
200 */
201 typedef size_t Size;
202
203 #define BUFFERALIGN(len) MAXALIGN(len)
204 #define UINT64CONST(x) (x##ULL)
205
206 /* PG checks for query cancellation in long loops; nothing to do standalone. */
207 #define CHECK_FOR_INTERRUPTS() ((void)0)
208
209 /* The wait-event class is PG instrumentation; the barrier/latch shims ignore
210 * the argument, so any value will do. */
211 #define WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN 0
212
213 /*
214 * Standalone Relation: the parallel build's "heap" carries the in-memory
215 * vector array it scans; its "index" carries a live page count so the few
216 * RelationGetNumberOfBlocks() call sites resolve. The shared driver never
217 * dereferences a Relation directly — the standalone back-end opens these out
218 * of its shared state — so only RelationGetNumberOfBlocks needs the fields.
219 */
220 typedef struct RelationData
221 {
222 const float *vectors; /* heap: vectors[nvecs * dim] */
223 uint32_t nvecs; /* heap: vector count */
224 uint32_t dim; /* heap: dimension */
225 const uint32_t *page_count; /* index: live page count (NULL for a heap) */
226 } RelationData;
227
228 typedef struct RelationData *Relation;
229
230 static inline BlockNumber
231 270 RelationGetNumberOfBlocks(Relation rel)
232 {
233
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 188 times.
270 if (rel->page_count != NULL)
234 82 return (BlockNumber)*rel->page_count;
235
236 /*
237 * Heap: report a block count from which the build's row estimate
238 * (blocks * BLCKSZ / bytes-per-tuple) recovers the true vector count.
239 */
240 188 uint64_t bytes_per_tuple = (uint64_t)rel->dim * sizeof(float) + 32;
241 188 return (BlockNumber)(((uint64_t)rel->nvecs * bytes_per_tuple + BLCKSZ -
242 188 1) /
243 BLCKSZ);
244 }
245
246 /*
247 * The shared build asks for an IndexInfo only to read ii_ParallelWorkers (the
248 * leader) and to hand back to prism_build_scan (ignored in standalone). A
249 * small struct covers both; BuildIndexInfo is unused by the standalone scan.
250 */
251 typedef struct IndexInfo
252 {
253 int ii_ParallelWorkers;
254 } IndexInfo;
255
256 static inline IndexInfo *
257 106 BuildIndexInfo(Relation rel)
258 {
259 (void)rel;
260 106 return NULL;
261 }
262
263 /* PG per-worker instrumentation — no-ops in standalone (single process). */
264 typedef struct WalUsage
265 {
266 int unused;
267 } WalUsage;
268
269 typedef struct BufferUsage
270 {
271 int unused;
272 } BufferUsage;
273
274 #define InstrAccumParallelQuery(buf, wal) ((void)(buf), (void)(wal))
275
276 #endif /* VS_STANDALONE */
277 #endif /* VS_PG_COMPAT_H */
278