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 :
22 2 : 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 4 : PG_FUNCTION_INFO_V1(dihandler);
58 :
59 : /*
60 : * Validation function for string relation options.
61 : */
62 : static void
63 68 : validate_string_option(const char *value)
64 : {
65 68 : ereport(NOTICE,
66 : (errmsg("new option value for string parameter %s",
67 : value ? value : "NULL")));
68 68 : }
69 :
70 : /*
71 : * This function creates a full set of relation option types,
72 : * with various patterns.
73 : */
74 : static void
75 2 : create_reloptions_table(void)
76 : {
77 2 : int i = 0;
78 :
79 2 : di_relopt_kind = add_reloption_kind();
80 :
81 2 : add_int_reloption(di_relopt_kind, "option_int",
82 : "Integer option for dummy_index_am",
83 : 10, -10, 100, AccessExclusiveLock);
84 2 : di_relopt_tab[i].optname = "option_int";
85 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_INT;
86 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_int);
87 2 : i++;
88 :
89 2 : add_real_reloption(di_relopt_kind, "option_real",
90 : "Real option for dummy_index_am",
91 : 3.1415, -10, 100, AccessExclusiveLock);
92 2 : di_relopt_tab[i].optname = "option_real";
93 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_REAL;
94 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_real);
95 2 : i++;
96 :
97 2 : add_bool_reloption(di_relopt_kind, "option_bool",
98 : "Boolean option for dummy_index_am",
99 : true, AccessExclusiveLock);
100 2 : di_relopt_tab[i].optname = "option_bool";
101 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_BOOL;
102 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_bool);
103 2 : i++;
104 :
105 2 : add_ternary_reloption(di_relopt_kind, "option_ternary_1",
106 : "One ternary option for dummy_index_am",
107 : AccessExclusiveLock);
108 2 : di_relopt_tab[i].optname = "option_ternary_1";
109 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_TERNARY;
110 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_ternary_1);
111 2 : i++;
112 :
113 2 : 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);
119 2 : di_relopt_tab[i].optname = "option_enum";
120 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_ENUM;
121 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_enum);
122 2 : i++;
123 :
124 2 : 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);
128 2 : di_relopt_tab[i].optname = "option_string_val";
129 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_STRING;
130 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions,
131 : option_string_val_offset);
132 2 : i++;
133 :
134 : /*
135 : * String option for dummy_index_am with NULL default, and without
136 : * description.
137 : */
138 2 : add_string_reloption(di_relopt_kind, "option_string_null",
139 : NULL, /* description */
140 : NULL, &validate_string_option,
141 : AccessExclusiveLock);
142 2 : di_relopt_tab[i].optname = "option_string_null";
143 2 : di_relopt_tab[i].opttype = RELOPT_TYPE_STRING;
144 2 : di_relopt_tab[i].offset = offsetof(DummyIndexOptions,
145 : option_string_null_offset);
146 2 : i++;
147 2 : }
148 :
149 :
150 : /*
151 : * Build a new index.
152 : */
153 : static IndexBuildResult *
154 4 : dibuild(Relation heap, Relation index, IndexInfo *indexInfo)
155 : {
156 : IndexBuildResult *result;
157 :
158 4 : result = palloc_object(IndexBuildResult);
159 :
160 : /* let's pretend that no tuples were scanned */
161 4 : result->heap_tuples = 0;
162 : /* and no index tuples were created (that is true) */
163 4 : result->index_tuples = 0;
164 :
165 4 : return result;
166 : }
167 :
168 : /*
169 : * Build an empty index for the initialization fork.
170 : */
171 : static void
172 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 *
239 162 : dioptions(Datum reloptions, bool validate)
240 : {
241 162 : 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
251 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
294 78 : 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 :
346 78 : PG_RETURN_POINTER(&amroutine);
347 : }
348 :
349 : void
350 2 : _PG_init(void)
351 : {
352 2 : create_reloptions_table();
353 2 : }
|