1 /*-------------------------------------------------------------------------
4 * Core support for relation options (pg_class.reloptions)
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
18 #include "access/reloptions.h"
19 #include "catalog/pg_type.h"
20 #include "commands/defrem.h"
21 #include "nodes/makefuncs.h"
22 #include "utils/array.h"
23 #include "utils/builtins.h"
24 #include "utils/guc.h"
25 #include "utils/rel.h"
29 * Transform a relation options list (list of DefElem) into the text array
30 * format that is kept in pg_class.reloptions.
32 * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
33 * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
34 * reloptions value (possibly NULL), and we replace or remove entries
37 * If ignoreOids is true, then we should ignore any occurrence of "oids"
38 * in the list (it will be or has been handled by interpretOidsOption()).
40 * Note that this is not responsible for determining whether the options
43 * Both oldOptions and the result are text arrays (or NULL for "default"),
44 * but we declare them as Datums to avoid including array.h in reloptions.h.
47 transformRelOptions(Datum oldOptions
, List
*defList
,
48 bool ignoreOids
, bool isReset
)
51 ArrayBuildState
*astate
;
54 /* no change if empty list */
58 /* We build new array using accumArrayResult */
61 /* Copy any oldOptions that aren't to be replaced */
62 if (PointerIsValid(DatumGetPointer(oldOptions
)))
64 ArrayType
*array
= DatumGetArrayTypeP(oldOptions
);
69 Assert(ARR_ELEMTYPE(array
) == TEXTOID
);
71 deconstruct_array(array
, TEXTOID
, -1, false, 'i',
72 &oldoptions
, NULL
, &noldoptions
);
74 for (i
= 0; i
< noldoptions
; i
++)
76 text
*oldoption
= DatumGetTextP(oldoptions
[i
]);
77 char *text_str
= VARDATA(oldoption
);
78 int text_len
= VARSIZE(oldoption
) - VARHDRSZ
;
80 /* Search for a match in defList */
81 foreach(cell
, defList
)
83 DefElem
*def
= lfirst(cell
);
84 int kw_len
= strlen(def
->defname
);
86 if (text_len
> kw_len
&& text_str
[kw_len
] == '=' &&
87 pg_strncasecmp(text_str
, def
->defname
, kw_len
) == 0)
92 /* No match, so keep old option */
93 astate
= accumArrayResult(astate
, oldoptions
[i
],
95 CurrentMemoryContext
);
101 * If CREATE/SET, add new options to array; if RESET, just check that the
102 * user didn't say RESET (option=val). (Must do this because the grammar
103 * doesn't enforce it.)
105 foreach(cell
, defList
)
107 DefElem
*def
= lfirst(cell
);
111 if (def
->arg
!= NULL
)
113 (errcode(ERRCODE_SYNTAX_ERROR
),
114 errmsg("RESET must not include values for parameters")));
122 if (ignoreOids
&& pg_strcasecmp(def
->defname
, "oids") == 0)
126 * Flatten the DefElem into a text string like "name=arg". If we
127 * have just "name", assume "name=true" is meant.
129 if (def
->arg
!= NULL
)
130 value
= defGetString(def
);
133 len
= VARHDRSZ
+ strlen(def
->defname
) + 1 + strlen(value
);
134 /* +1 leaves room for sprintf's trailing null */
135 t
= (text
*) palloc(len
+ 1);
137 sprintf(VARDATA(t
), "%s=%s", def
->defname
, value
);
139 astate
= accumArrayResult(astate
, PointerGetDatum(t
),
141 CurrentMemoryContext
);
146 result
= makeArrayResult(astate
, CurrentMemoryContext
);
155 * Convert the text-array format of reloptions into a List of DefElem.
156 * This is the inverse of transformRelOptions().
159 untransformRelOptions(Datum options
)
167 /* Nothing to do if no options */
168 if (!PointerIsValid(DatumGetPointer(options
)))
171 array
= DatumGetArrayTypeP(options
);
173 Assert(ARR_ELEMTYPE(array
) == TEXTOID
);
175 deconstruct_array(array
, TEXTOID
, -1, false, 'i',
176 &optiondatums
, NULL
, &noptions
);
178 for (i
= 0; i
< noptions
; i
++)
184 s
= TextDatumGetCString(optiondatums
[i
]);
189 val
= (Node
*) makeString(pstrdup(p
));
191 result
= lappend(result
, makeDefElem(pstrdup(s
), val
));
199 * Interpret reloptions that are given in text-array format.
201 * options: array of "keyword=value" strings, as built by transformRelOptions
202 * numkeywords: number of legal keywords
203 * keywords: the allowed keywords
204 * values: output area
205 * validate: if true, throw error for unrecognized keywords.
207 * The keywords and values arrays must both be of length numkeywords.
208 * The values entry corresponding to a keyword is set to a palloc'd string
209 * containing the corresponding value, or NULL if the keyword does not appear.
212 parseRelOptions(Datum options
, int numkeywords
, const char *const * keywords
,
213 char **values
, bool validate
)
220 /* Initialize to "all defaulted" */
221 MemSet(values
, 0, numkeywords
* sizeof(char *));
223 /* Done if no options */
224 if (!PointerIsValid(DatumGetPointer(options
)))
227 array
= DatumGetArrayTypeP(options
);
229 Assert(ARR_ELEMTYPE(array
) == TEXTOID
);
231 deconstruct_array(array
, TEXTOID
, -1, false, 'i',
232 &optiondatums
, NULL
, &noptions
);
234 for (i
= 0; i
< noptions
; i
++)
236 text
*optiontext
= DatumGetTextP(optiondatums
[i
]);
237 char *text_str
= VARDATA(optiontext
);
238 int text_len
= VARSIZE(optiontext
) - VARHDRSZ
;
241 /* Search for a match in keywords */
242 for (j
= 0; j
< numkeywords
; j
++)
244 int kw_len
= strlen(keywords
[j
]);
246 if (text_len
> kw_len
&& text_str
[kw_len
] == '=' &&
247 pg_strncasecmp(text_str
, keywords
[j
], kw_len
) == 0)
252 if (values
[j
] && validate
)
254 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
255 errmsg("parameter \"%s\" specified more than once",
257 value_len
= text_len
- kw_len
- 1;
258 value
= (char *) palloc(value_len
+ 1);
259 memcpy(value
, text_str
+ kw_len
+ 1, value_len
);
260 value
[value_len
] = '\0';
265 if (j
>= numkeywords
&& validate
)
270 s
= TextDatumGetCString(optiondatums
[i
]);
275 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
276 errmsg("unrecognized parameter \"%s\"", s
)));
283 * Parse reloptions for anything using StdRdOptions (ie, fillfactor only)
286 default_reloptions(Datum reloptions
, bool validate
,
287 int minFillfactor
, int defaultFillfactor
)
289 static const char *const default_keywords
[1] = {"fillfactor"};
292 StdRdOptions
*result
;
294 parseRelOptions(reloptions
, 1, default_keywords
, values
, validate
);
297 * If no options, we can just return NULL rather than doing anything.
298 * (defaultFillfactor is thus not used, but we require callers to pass it
299 * anyway since we would need it if more options were added.)
301 if (values
[0] == NULL
)
304 if (!parse_int(values
[0], &fillfactor
, 0, NULL
))
308 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
309 errmsg("fillfactor must be an integer: \"%s\"",
314 if (fillfactor
< minFillfactor
|| fillfactor
> 100)
318 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
319 errmsg("fillfactor=%d is out of range (should be between %d and 100)",
320 fillfactor
, minFillfactor
)));
324 result
= (StdRdOptions
*) palloc(sizeof(StdRdOptions
));
325 SET_VARSIZE(result
, sizeof(StdRdOptions
));
327 result
->fillfactor
= fillfactor
;
329 return (bytea
*) result
;
334 * Parse options for heaps (and perhaps someday toast tables).
337 heap_reloptions(char relkind
, Datum reloptions
, bool validate
)
339 return default_reloptions(reloptions
, validate
,
341 HEAP_DEFAULT_FILLFACTOR
);
346 * Parse options for indexes.
348 * amoptions Oid of option parser
349 * reloptions options as text[] datum
350 * validate error flag
353 index_reloptions(RegProcedure amoptions
, Datum reloptions
, bool validate
)
356 FunctionCallInfoData fcinfo
;
359 Assert(RegProcedureIsValid(amoptions
));
361 /* Assume function is strict */
362 if (!PointerIsValid(DatumGetPointer(reloptions
)))
365 /* Can't use OidFunctionCallN because we might get a NULL result */
366 fmgr_info(amoptions
, &flinfo
);
368 InitFunctionCallInfoData(fcinfo
, &flinfo
, 2, NULL
, NULL
);
370 fcinfo
.arg
[0] = reloptions
;
371 fcinfo
.arg
[1] = BoolGetDatum(validate
);
372 fcinfo
.argnull
[0] = false;
373 fcinfo
.argnull
[1] = false;
375 result
= FunctionCallInvoke(&fcinfo
);
377 if (fcinfo
.isnull
|| DatumGetPointer(result
) == NULL
)
380 return DatumGetByteaP(result
);