Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * dummy_index_am.c
4 : * Index AM template main file.
5 : *
6 : * Portions Copyright (c) 1996-2024, 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[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 4 : PG_FUNCTION_INFO_V1(dihandler);
57 :
58 : /*
59 : * Validation function for string relation options.
60 : */
61 : static void
62 60 : validate_string_option(const char *value)
63 : {
64 60 : ereport(NOTICE,
65 : (errmsg("new option value for string parameter %s",
66 : value ? value : "NULL")));
67 60 : }
68 :
69 : /*
70 : * This function creates a full set of relation option types,
71 : * with various patterns.
72 : */
73 : static void
74 2 : create_reloptions_table(void)
75 : {
76 2 : di_relopt_kind = add_reloption_kind();
77 :
78 2 : add_int_reloption(di_relopt_kind, "option_int",
79 : "Integer option for dummy_index_am",
80 : 10, -10, 100, AccessExclusiveLock);
81 2 : di_relopt_tab[0].optname = "option_int";
82 2 : di_relopt_tab[0].opttype = RELOPT_TYPE_INT;
83 2 : di_relopt_tab[0].offset = offsetof(DummyIndexOptions, option_int);
84 :
85 2 : add_real_reloption(di_relopt_kind, "option_real",
86 : "Real option for dummy_index_am",
87 : 3.1415, -10, 100, AccessExclusiveLock);
88 2 : di_relopt_tab[1].optname = "option_real";
89 2 : di_relopt_tab[1].opttype = RELOPT_TYPE_REAL;
90 2 : di_relopt_tab[1].offset = offsetof(DummyIndexOptions, option_real);
91 :
92 2 : add_bool_reloption(di_relopt_kind, "option_bool",
93 : "Boolean option for dummy_index_am",
94 : true, AccessExclusiveLock);
95 2 : di_relopt_tab[2].optname = "option_bool";
96 2 : di_relopt_tab[2].opttype = RELOPT_TYPE_BOOL;
97 2 : di_relopt_tab[2].offset = offsetof(DummyIndexOptions, option_bool);
98 :
99 2 : 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 2 : di_relopt_tab[3].optname = "option_enum";
106 2 : di_relopt_tab[3].opttype = RELOPT_TYPE_ENUM;
107 2 : di_relopt_tab[3].offset = offsetof(DummyIndexOptions, option_enum);
108 :
109 2 : 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);
113 2 : di_relopt_tab[4].optname = "option_string_val";
114 2 : di_relopt_tab[4].opttype = RELOPT_TYPE_STRING;
115 2 : 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 : */
122 2 : add_string_reloption(di_relopt_kind, "option_string_null",
123 : NULL, /* description */
124 : NULL, &validate_string_option,
125 : AccessExclusiveLock);
126 2 : di_relopt_tab[5].optname = "option_string_null";
127 2 : di_relopt_tab[5].opttype = RELOPT_TYPE_STRING;
128 2 : di_relopt_tab[5].offset = offsetof(DummyIndexOptions,
129 : option_string_null_offset);
130 2 : }
131 :
132 :
133 : /*
134 : * Build a new index.
135 : */
136 : static IndexBuildResult *
137 4 : dibuild(Relation heap, Relation index, IndexInfo *indexInfo)
138 : {
139 : IndexBuildResult *result;
140 :
141 4 : result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
142 :
143 : /* let's pretend that no tuples were scanned */
144 4 : result->heap_tuples = 0;
145 : /* and no index tuples were created (that is true) */
146 4 : result->index_tuples = 0;
147 :
148 4 : return result;
149 : }
150 :
151 : /*
152 : * Build an empty index for the initialization fork.
153 : */
154 : static void
155 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 *
222 138 : dioptions(Datum reloptions, bool validate)
223 : {
224 138 : 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
234 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
277 66 : dihandler(PG_FUNCTION_ARGS)
278 : {
279 66 : IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
280 :
281 66 : amroutine->amstrategies = 0;
282 66 : amroutine->amsupport = 1;
283 66 : amroutine->amcanorder = false;
284 66 : amroutine->amcanorderbyop = false;
285 66 : amroutine->amcanbackward = false;
286 66 : amroutine->amcanunique = false;
287 66 : amroutine->amcanmulticol = false;
288 66 : amroutine->amoptionalkey = false;
289 66 : amroutine->amsearcharray = false;
290 66 : amroutine->amsearchnulls = false;
291 66 : amroutine->amstorage = false;
292 66 : amroutine->amclusterable = false;
293 66 : amroutine->ampredlocks = false;
294 66 : amroutine->amcanparallel = false;
295 66 : amroutine->amcanbuildparallel = false;
296 66 : amroutine->amcaninclude = false;
297 66 : amroutine->amusemaintenanceworkmem = false;
298 66 : amroutine->amsummarizing = false;
299 66 : amroutine->amparallelvacuumoptions = VACUUM_OPTION_NO_PARALLEL;
300 66 : amroutine->amkeytype = InvalidOid;
301 :
302 66 : amroutine->ambuild = dibuild;
303 66 : amroutine->ambuildempty = dibuildempty;
304 66 : amroutine->aminsert = diinsert;
305 66 : amroutine->ambulkdelete = dibulkdelete;
306 66 : amroutine->amvacuumcleanup = divacuumcleanup;
307 66 : amroutine->amcanreturn = NULL;
308 66 : amroutine->amcostestimate = dicostestimate;
309 66 : amroutine->amgettreeheight = NULL;
310 66 : amroutine->amoptions = dioptions;
311 66 : amroutine->amproperty = NULL;
312 66 : amroutine->ambuildphasename = NULL;
313 66 : amroutine->amvalidate = divalidate;
314 66 : amroutine->ambeginscan = dibeginscan;
315 66 : amroutine->amrescan = direscan;
316 66 : amroutine->amgettuple = NULL;
317 66 : amroutine->amgetbitmap = NULL;
318 66 : amroutine->amendscan = diendscan;
319 66 : amroutine->ammarkpos = NULL;
320 66 : amroutine->amrestrpos = NULL;
321 66 : amroutine->amestimateparallelscan = NULL;
322 66 : amroutine->aminitparallelscan = NULL;
323 66 : amroutine->amparallelrescan = NULL;
324 :
325 66 : PG_RETURN_POINTER(amroutine);
326 : }
327 :
328 : void
329 2 : _PG_init(void)
330 : {
331 2 : create_reloptions_table();
332 2 : }
|