Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / access / common / reloptions.c
blobdb39d90d0286f6c1999787de6b2ebda5be0662c7
1 /*-------------------------------------------------------------------------
3 * reloptions.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
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
35 * as needed.
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
41 * are valid.
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.
46 Datum
47 transformRelOptions(Datum oldOptions, List *defList,
48 bool ignoreOids, bool isReset)
50 Datum result;
51 ArrayBuildState *astate;
52 ListCell *cell;
54 /* no change if empty list */
55 if (defList == NIL)
56 return oldOptions;
58 /* We build new array using accumArrayResult */
59 astate = NULL;
61 /* Copy any oldOptions that aren't to be replaced */
62 if (PointerIsValid(DatumGetPointer(oldOptions)))
64 ArrayType *array = DatumGetArrayTypeP(oldOptions);
65 Datum *oldoptions;
66 int noldoptions;
67 int i;
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)
88 break;
90 if (!cell)
92 /* No match, so keep old option */
93 astate = accumArrayResult(astate, oldoptions[i],
94 false, TEXTOID,
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);
109 if (isReset)
111 if (def->arg != NULL)
112 ereport(ERROR,
113 (errcode(ERRCODE_SYNTAX_ERROR),
114 errmsg("RESET must not include values for parameters")));
116 else
118 text *t;
119 const char *value;
120 Size len;
122 if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
123 continue;
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);
131 else
132 value = "true";
133 len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
134 /* +1 leaves room for sprintf's trailing null */
135 t = (text *) palloc(len + 1);
136 SET_VARSIZE(t, len);
137 sprintf(VARDATA(t), "%s=%s", def->defname, value);
139 astate = accumArrayResult(astate, PointerGetDatum(t),
140 false, TEXTOID,
141 CurrentMemoryContext);
145 if (astate)
146 result = makeArrayResult(astate, CurrentMemoryContext);
147 else
148 result = (Datum) 0;
150 return result;
155 * Convert the text-array format of reloptions into a List of DefElem.
156 * This is the inverse of transformRelOptions().
158 List *
159 untransformRelOptions(Datum options)
161 List *result = NIL;
162 ArrayType *array;
163 Datum *optiondatums;
164 int noptions;
165 int i;
167 /* Nothing to do if no options */
168 if (!PointerIsValid(DatumGetPointer(options)))
169 return result;
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++)
180 char *s;
181 char *p;
182 Node *val = NULL;
184 s = TextDatumGetCString(optiondatums[i]);
185 p = strchr(s, '=');
186 if (p)
188 *p++ = '\0';
189 val = (Node *) makeString(pstrdup(p));
191 result = lappend(result, makeDefElem(pstrdup(s), val));
194 return result;
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.
211 void
212 parseRelOptions(Datum options, int numkeywords, const char *const * keywords,
213 char **values, bool validate)
215 ArrayType *array;
216 Datum *optiondatums;
217 int noptions;
218 int i;
220 /* Initialize to "all defaulted" */
221 MemSet(values, 0, numkeywords * sizeof(char *));
223 /* Done if no options */
224 if (!PointerIsValid(DatumGetPointer(options)))
225 return;
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;
239 int j;
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)
249 char *value;
250 int value_len;
252 if (values[j] && validate)
253 ereport(ERROR,
254 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
255 errmsg("parameter \"%s\" specified more than once",
256 keywords[j])));
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';
261 values[j] = value;
262 break;
265 if (j >= numkeywords && validate)
267 char *s;
268 char *p;
270 s = TextDatumGetCString(optiondatums[i]);
271 p = strchr(s, '=');
272 if (p)
273 *p = '\0';
274 ereport(ERROR,
275 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
276 errmsg("unrecognized parameter \"%s\"", s)));
283 * Parse reloptions for anything using StdRdOptions (ie, fillfactor only)
285 bytea *
286 default_reloptions(Datum reloptions, bool validate,
287 int minFillfactor, int defaultFillfactor)
289 static const char *const default_keywords[1] = {"fillfactor"};
290 char *values[1];
291 int 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)
302 return NULL;
304 if (!parse_int(values[0], &fillfactor, 0, NULL))
306 if (validate)
307 ereport(ERROR,
308 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
309 errmsg("fillfactor must be an integer: \"%s\"",
310 values[0])));
311 return NULL;
314 if (fillfactor < minFillfactor || fillfactor > 100)
316 if (validate)
317 ereport(ERROR,
318 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
319 errmsg("fillfactor=%d is out of range (should be between %d and 100)",
320 fillfactor, minFillfactor)));
321 return NULL;
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).
336 bytea *
337 heap_reloptions(char relkind, Datum reloptions, bool validate)
339 return default_reloptions(reloptions, validate,
340 HEAP_MIN_FILLFACTOR,
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
352 bytea *
353 index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
355 FmgrInfo flinfo;
356 FunctionCallInfoData fcinfo;
357 Datum result;
359 Assert(RegProcedureIsValid(amoptions));
361 /* Assume function is strict */
362 if (!PointerIsValid(DatumGetPointer(reloptions)))
363 return NULL;
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)
378 return NULL;
380 return DatumGetByteaP(result);