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