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