Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * dummy_index_am.c
4 : : * Index AM template main file.
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : * IDENTIFICATION
10 : : * src/test/modules/dummy_index_am/dummy_index_am.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : : #include "postgres.h"
15 : :
16 : : #include "access/amapi.h"
17 : : #include "access/reloptions.h"
18 : : #include "catalog/index.h"
19 : : #include "commands/vacuum.h"
20 : : #include "nodes/pathnodes.h"
21 : :
2363 michael@paquier.xyz 22 :CBC 1 : PG_MODULE_MAGIC;
23 : :
24 : : /* parse table for fillRelOptions */
25 : : static relopt_parse_elt di_relopt_tab[8];
26 : :
27 : : /* Kind of relation options for dummy index */
28 : : static relopt_kind di_relopt_kind;
29 : :
30 : : typedef enum DummyAmEnum
31 : : {
32 : : DUMMY_AM_ENUM_ONE,
33 : : DUMMY_AM_ENUM_TWO,
34 : : } DummyAmEnum;
35 : :
36 : : /* Dummy index options */
37 : : typedef struct DummyIndexOptions
38 : : {
39 : : int32 vl_len_; /* varlena header (do not touch directly!) */
40 : : int option_int;
41 : : double option_real;
42 : : bool option_bool;
43 : : pg_ternary option_ternary_1;
44 : : DummyAmEnum option_enum;
45 : : int option_string_val_offset;
46 : : int option_string_null_offset;
47 : : } DummyIndexOptions;
48 : :
49 : : static relopt_enum_elt_def dummyAmEnumValues[] =
50 : : {
51 : : {"one", DUMMY_AM_ENUM_ONE},
52 : : {"two", DUMMY_AM_ENUM_TWO},
53 : : {(const char *) NULL} /* list terminator */
54 : : };
55 : :
56 : : /* Handler for index AM */
57 : 2 : PG_FUNCTION_INFO_V1(dihandler);
58 : :
59 : : /*
60 : : * Validation function for string relation options.
61 : : */
62 : : static void
63 : 34 : validate_string_option(const char *value)
64 : : {
65 [ + + + - ]: 34 : ereport(NOTICE,
66 : : (errmsg("new option value for string parameter %s",
67 : : value ? value : "NULL")));
68 : 34 : }
69 : :
70 : : /*
71 : : * This function creates a full set of relation option types,
72 : : * with various patterns.
73 : : */
74 : : static void
75 : 1 : create_reloptions_table(void)
76 : : {
53 alvherre@kurilemu.de 77 :GNC 1 : int i = 0;
78 : :
2363 michael@paquier.xyz 79 :CBC 1 : di_relopt_kind = add_reloption_kind();
80 : :
81 : 1 : add_int_reloption(di_relopt_kind, "option_int",
82 : : "Integer option for dummy_index_am",
83 : : 10, -10, 100, AccessExclusiveLock);
53 alvherre@kurilemu.de 84 :GNC 1 : di_relopt_tab[i].optname = "option_int";
85 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_INT;
86 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_int);
87 : 1 : i++;
88 : :
2363 michael@paquier.xyz 89 :CBC 1 : add_real_reloption(di_relopt_kind, "option_real",
90 : : "Real option for dummy_index_am",
91 : : 3.1415, -10, 100, AccessExclusiveLock);
53 alvherre@kurilemu.de 92 :GNC 1 : di_relopt_tab[i].optname = "option_real";
93 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_REAL;
94 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_real);
95 : 1 : i++;
96 : :
2363 michael@paquier.xyz 97 :CBC 1 : add_bool_reloption(di_relopt_kind, "option_bool",
98 : : "Boolean option for dummy_index_am",
99 : : true, AccessExclusiveLock);
53 alvherre@kurilemu.de 100 :GNC 1 : di_relopt_tab[i].optname = "option_bool";
101 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_BOOL;
102 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_bool);
103 : 1 : i++;
104 : :
105 : 1 : add_ternary_reloption(di_relopt_kind, "option_ternary_1",
106 : : "One ternary option for dummy_index_am",
107 : : AccessExclusiveLock);
108 : 1 : di_relopt_tab[i].optname = "option_ternary_1";
109 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_TERNARY;
110 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_ternary_1);
111 : 1 : i++;
112 : :
2363 alvherre@alvh.no-ip. 113 :CBC 1 : add_enum_reloption(di_relopt_kind, "option_enum",
114 : : "Enum option for dummy_index_am",
115 : : dummyAmEnumValues,
116 : : DUMMY_AM_ENUM_ONE,
117 : : "Valid values are \"one\" and \"two\".",
118 : : AccessExclusiveLock);
53 alvherre@kurilemu.de 119 :GNC 1 : di_relopt_tab[i].optname = "option_enum";
120 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_ENUM;
121 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_enum);
122 : 1 : i++;
123 : :
2363 michael@paquier.xyz 124 :CBC 1 : add_string_reloption(di_relopt_kind, "option_string_val",
125 : : "String option for dummy_index_am with non-NULL default",
126 : : "DefaultValue", &validate_string_option,
127 : : AccessExclusiveLock);
53 alvherre@kurilemu.de 128 :GNC 1 : di_relopt_tab[i].optname = "option_string_val";
129 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_STRING;
130 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions,
131 : : option_string_val_offset);
132 : 1 : i++;
133 : :
134 : : /*
135 : : * String option for dummy_index_am with NULL default, and without
136 : : * description.
137 : : */
2363 michael@paquier.xyz 138 :CBC 1 : add_string_reloption(di_relopt_kind, "option_string_null",
139 : : NULL, /* description */
140 : : NULL, &validate_string_option,
141 : : AccessExclusiveLock);
53 alvherre@kurilemu.de 142 :GNC 1 : di_relopt_tab[i].optname = "option_string_null";
143 : 1 : di_relopt_tab[i].opttype = RELOPT_TYPE_STRING;
144 : 1 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions,
145 : : option_string_null_offset);
146 : 1 : i++;
2363 michael@paquier.xyz 147 :CBC 1 : }
148 : :
149 : :
150 : : /*
151 : : * Build a new index.
152 : : */
153 : : static IndexBuildResult *
154 : 2 : dibuild(Relation heap, Relation index, IndexInfo *indexInfo)
155 : : {
156 : : IndexBuildResult *result;
157 : :
96 michael@paquier.xyz 158 :GNC 2 : result = palloc_object(IndexBuildResult);
159 : :
160 : : /* let's pretend that no tuples were scanned */
2363 michael@paquier.xyz 161 :CBC 2 : result->heap_tuples = 0;
162 : : /* and no index tuples were created (that is true) */
163 : 2 : result->index_tuples = 0;
164 : :
165 : 2 : return result;
166 : : }
167 : :
168 : : /*
169 : : * Build an empty index for the initialization fork.
170 : : */
171 : : static void
2363 michael@paquier.xyz 172 :UBC 0 : dibuildempty(Relation index)
173 : : {
174 : : /* No need to build an init fork for a dummy index */
175 : 0 : }
176 : :
177 : : /*
178 : : * Insert new tuple to index AM.
179 : : */
180 : : static bool
181 : 0 : diinsert(Relation index, Datum *values, bool *isnull,
182 : : ItemPointer ht_ctid, Relation heapRel,
183 : : IndexUniqueCheck checkUnique,
184 : : bool indexUnchanged,
185 : : IndexInfo *indexInfo)
186 : : {
187 : : /* nothing to do */
188 : 0 : return false;
189 : : }
190 : :
191 : : /*
192 : : * Bulk deletion of all index entries pointing to a set of table tuples.
193 : : */
194 : : static IndexBulkDeleteResult *
195 : 0 : dibulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
196 : : IndexBulkDeleteCallback callback, void *callback_state)
197 : : {
198 : : /*
199 : : * There is nothing to delete. Return NULL as there is nothing to pass to
200 : : * amvacuumcleanup.
201 : : */
202 : 0 : return NULL;
203 : : }
204 : :
205 : : /*
206 : : * Post-VACUUM cleanup for index AM.
207 : : */
208 : : static IndexBulkDeleteResult *
209 : 0 : divacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
210 : : {
211 : : /* Index has not been modified, so returning NULL is fine */
212 : 0 : return NULL;
213 : : }
214 : :
215 : : /*
216 : : * Estimate cost of index AM.
217 : : */
218 : : static void
219 : 0 : dicostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
220 : : Cost *indexStartupCost, Cost *indexTotalCost,
221 : : Selectivity *indexSelectivity, double *indexCorrelation,
222 : : double *indexPages)
223 : : {
224 : : /* Tell planner to never use this index! */
225 : 0 : *indexStartupCost = 1.0e10;
226 : 0 : *indexTotalCost = 1.0e10;
227 : :
228 : : /* Do not care about the rest */
229 : 0 : *indexSelectivity = 1;
230 : 0 : *indexCorrelation = 0;
231 : 0 : *indexPages = 1;
232 : 0 : }
233 : :
234 : : /*
235 : : * Parse relation options for index AM, returning a DummyIndexOptions
236 : : * structure filled with option values.
237 : : */
238 : : static bytea *
2363 michael@paquier.xyz 239 :CBC 81 : dioptions(Datum reloptions, bool validate)
240 : : {
2322 241 : 81 : return (bytea *) build_reloptions(reloptions, validate,
242 : : di_relopt_kind,
243 : : sizeof(DummyIndexOptions),
244 : : di_relopt_tab, lengthof(di_relopt_tab));
245 : : }
246 : :
247 : : /*
248 : : * Validator for index AM.
249 : : */
250 : : static bool
2363 michael@paquier.xyz 251 :UBC 0 : divalidate(Oid opclassoid)
252 : : {
253 : : /* Index is dummy so we are happy with any opclass */
254 : 0 : return true;
255 : : }
256 : :
257 : : /*
258 : : * Begin scan of index AM.
259 : : */
260 : : static IndexScanDesc
261 : 0 : dibeginscan(Relation r, int nkeys, int norderbys)
262 : : {
263 : : IndexScanDesc scan;
264 : :
265 : : /* Let's pretend we are doing something */
266 : 0 : scan = RelationGetIndexScan(r, nkeys, norderbys);
267 : 0 : return scan;
268 : : }
269 : :
270 : : /*
271 : : * Rescan of index AM.
272 : : */
273 : : static void
274 : 0 : direscan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
275 : : ScanKey orderbys, int norderbys)
276 : : {
277 : : /* nothing to do */
278 : 0 : }
279 : :
280 : : /*
281 : : * End scan of index AM.
282 : : */
283 : : static void
284 : 0 : diendscan(IndexScanDesc scan)
285 : : {
286 : : /* nothing to do */
287 : 0 : }
288 : :
289 : : /*
290 : : * Index AM handler function: returns IndexAmRoutine with access method
291 : : * parameters and callbacks.
292 : : */
293 : : Datum
2363 michael@paquier.xyz 294 :CBC 39 : dihandler(PG_FUNCTION_ARGS)
295 : : {
296 : : static const IndexAmRoutine amroutine = {
297 : : .type = T_IndexAmRoutine,
298 : : .amstrategies = 0,
299 : : .amsupport = 1,
300 : : .amcanorder = false,
301 : : .amcanorderbyop = false,
302 : : .amcanhash = false,
303 : : .amconsistentequality = false,
304 : : .amconsistentordering = false,
305 : : .amcanbackward = false,
306 : : .amcanunique = false,
307 : : .amcanmulticol = false,
308 : : .amoptionalkey = false,
309 : : .amsearcharray = false,
310 : : .amsearchnulls = false,
311 : : .amstorage = false,
312 : : .amclusterable = false,
313 : : .ampredlocks = false,
314 : : .amcanparallel = false,
315 : : .amcanbuildparallel = false,
316 : : .amcaninclude = false,
317 : : .amusemaintenanceworkmem = false,
318 : : .amsummarizing = false,
319 : : .amparallelvacuumoptions = VACUUM_OPTION_NO_PARALLEL,
320 : : .amkeytype = InvalidOid,
321 : :
322 : : .ambuild = dibuild,
323 : : .ambuildempty = dibuildempty,
324 : : .aminsert = diinsert,
325 : : .ambulkdelete = dibulkdelete,
326 : : .amvacuumcleanup = divacuumcleanup,
327 : : .amcanreturn = NULL,
328 : : .amcostestimate = dicostestimate,
329 : : .amgettreeheight = NULL,
330 : : .amoptions = dioptions,
331 : : .amproperty = NULL,
332 : : .ambuildphasename = NULL,
333 : : .amvalidate = divalidate,
334 : : .ambeginscan = dibeginscan,
335 : : .amrescan = direscan,
336 : : .amgettuple = NULL,
337 : : .amgetbitmap = NULL,
338 : : .amendscan = diendscan,
339 : : .ammarkpos = NULL,
340 : : .amrestrpos = NULL,
341 : : .amestimateparallelscan = NULL,
342 : : .aminitparallelscan = NULL,
343 : : .amparallelrescan = NULL,
344 : : };
345 : :
75 tgl@sss.pgh.pa.us 346 :GNC 39 : PG_RETURN_POINTER(&amroutine);
347 : : }
348 : :
349 : : void
2363 michael@paquier.xyz 350 :CBC 1 : _PG_init(void)
351 : : {
352 : 1 : create_reloptions_table();
353 : 1 : }
|