Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * define.c
4 : : * Support routines for various kinds of object creation.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/backend/commands/define.c
13 : : *
14 : : * DESCRIPTION
15 : : * The "DefineFoo" routines take the parse tree and pick out the
16 : : * appropriate arguments/flags, passing the results to the
17 : : * corresponding "FooDefine" routines (in src/catalog) that do
18 : : * the actual catalog-munging. These routines also verify permission
19 : : * of the user to execute the command.
20 : : *
21 : : * NOTES
22 : : * These things must be defined and committed in the following order:
23 : : * "create function":
24 : : * input/output, recv/send procedures
25 : : * "create type":
26 : : * type
27 : : * "create operator":
28 : : * operators
29 : : *
30 : : *
31 : : *-------------------------------------------------------------------------
32 : : */
33 : : #include "postgres.h"
34 : :
35 : : #include <ctype.h>
36 : : #include <math.h>
37 : :
38 : : #include "catalog/namespace.h"
39 : : #include "commands/defrem.h"
40 : : #include "nodes/makefuncs.h"
41 : : #include "parser/parse_type.h"
42 : : #include "utils/fmgrprotos.h"
43 : :
44 : : /*
45 : : * Extract a string value (otherwise uninterpreted) from a DefElem.
46 : : */
47 : : char *
5489 tgl@sss.pgh.pa.us 48 :CBC 27448 : defGetString(DefElem *def)
49 : : {
50 [ - + ]: 27448 : if (def->arg == NULL)
7574 tgl@sss.pgh.pa.us 51 [ # # ]:UBC 0 : ereport(ERROR,
52 : : (errcode(ERRCODE_SYNTAX_ERROR),
53 : : errmsg("%s requires a parameter",
54 : : def->defname)));
5489 tgl@sss.pgh.pa.us 55 [ + + + + :CBC 27448 : switch (nodeTag(def->arg))
+ - - - ]
56 : : {
8590 57 : 524 : case T_Integer:
3751 peter_e@gmx.net 58 : 524 : return psprintf("%ld", (long) intVal(def->arg));
8590 tgl@sss.pgh.pa.us 59 : 53 : case T_Float:
821 peter@eisentraut.org 60 : 53 : return castNode(Float, def->arg)->fval;
61 : 275 : case T_Boolean:
62 [ + + ]: 275 : return boolVal(def->arg) ? "true" : "false";
8590 tgl@sss.pgh.pa.us 63 : 24359 : case T_String:
5489 64 : 24359 : return strVal(def->arg);
8590 65 : 2237 : case T_TypeName:
5489 66 : 2237 : return TypeNameToString((TypeName *) def->arg);
7918 tgl@sss.pgh.pa.us 67 :UBC 0 : case T_List:
5489 68 : 0 : return NameListToString((List *) def->arg);
5319 69 : 0 : case T_A_Star:
70 : 0 : return pstrdup("*");
8590 71 : 0 : default:
5489 72 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
73 : : }
74 : : return NULL; /* keep compiler quiet */
75 : : }
76 : :
77 : : /*
78 : : * Extract a numeric value (actually double) from a DefElem.
79 : : */
80 : : double
8961 tgl@sss.pgh.pa.us 81 :CBC 1910 : defGetNumeric(DefElem *def)
82 : : {
83 [ - + ]: 1910 : if (def->arg == NULL)
7574 tgl@sss.pgh.pa.us 84 [ # # ]:UBC 0 : ereport(ERROR,
85 : : (errcode(ERRCODE_SYNTAX_ERROR),
86 : : errmsg("%s requires a numeric value",
87 : : def->defname)));
8961 tgl@sss.pgh.pa.us 88 [ + + - ]:CBC 1910 : switch (nodeTag(def->arg))
89 : : {
90 : 1900 : case T_Integer:
91 : 1900 : return (double) intVal(def->arg);
92 : 10 : case T_Float:
93 : 10 : return floatVal(def->arg);
8961 tgl@sss.pgh.pa.us 94 :UBC 0 : default:
7574 95 [ # # ]: 0 : ereport(ERROR,
96 : : (errcode(ERRCODE_SYNTAX_ERROR),
97 : : errmsg("%s requires a numeric value",
98 : : def->defname)));
99 : : }
100 : : return 0; /* keep compiler quiet */
101 : : }
102 : :
103 : : /*
104 : : * Extract a boolean value from a DefElem.
105 : : */
106 : : bool
5489 tgl@sss.pgh.pa.us 107 :CBC 15999 : defGetBoolean(DefElem *def)
108 : : {
109 : : /*
110 : : * If no parameter value given, assume "true" is meant.
111 : : */
112 [ + + ]: 15999 : if (def->arg == NULL)
7275 113 : 7479 : return true;
114 : :
115 : : /*
116 : : * Allow 0, 1, "true", "false", "on", "off"
117 : : */
5489 118 [ + + ]: 8520 : switch (nodeTag(def->arg))
119 : : {
6496 bruce@momjian.us 120 : 221 : case T_Integer:
5489 tgl@sss.pgh.pa.us 121 [ + + + ]: 221 : switch (intVal(def->arg))
122 : : {
6495 123 : 189 : case 0:
124 : 189 : return false;
125 : 29 : case 1:
126 : 29 : return true;
127 : 3 : default:
128 : : /* otherwise, error out below */
129 : 3 : break;
130 : : }
6496 bruce@momjian.us 131 : 3 : break;
132 : 8299 : default:
133 : : {
5489 tgl@sss.pgh.pa.us 134 : 8299 : char *sval = defGetString(def);
135 : :
136 : : /*
137 : : * The set of strings accepted here should match up with the
138 : : * grammar's opt_boolean_or_string production.
139 : : */
6495 140 [ + + ]: 8299 : if (pg_strcasecmp(sval, "true") == 0)
141 : 769 : return true;
142 [ + + ]: 7530 : if (pg_strcasecmp(sval, "false") == 0)
143 : 676 : return false;
5376 144 [ + + ]: 6854 : if (pg_strcasecmp(sval, "on") == 0)
145 : 64 : return true;
146 [ + + ]: 6790 : if (pg_strcasecmp(sval, "off") == 0)
147 : 6781 : return false;
148 : : }
6496 bruce@momjian.us 149 : 9 : break;
150 : : }
7275 tgl@sss.pgh.pa.us 151 [ + - ]: 12 : ereport(ERROR,
152 : : (errcode(ERRCODE_SYNTAX_ERROR),
153 : : errmsg("%s requires a Boolean value",
154 : : def->defname)));
155 : : return false; /* keep compiler quiet */
156 : : }
157 : :
158 : : /*
159 : : * Extract an int32 value from a DefElem.
160 : : */
161 : : int32
3802 162 : 891 : defGetInt32(DefElem *def)
163 : : {
164 [ - + ]: 891 : if (def->arg == NULL)
3802 tgl@sss.pgh.pa.us 165 [ # # ]:UBC 0 : ereport(ERROR,
166 : : (errcode(ERRCODE_SYNTAX_ERROR),
167 : : errmsg("%s requires an integer value",
168 : : def->defname)));
3802 tgl@sss.pgh.pa.us 169 [ + - ]:CBC 891 : switch (nodeTag(def->arg))
170 : : {
171 : 891 : case T_Integer:
172 : 891 : return (int32) intVal(def->arg);
3802 tgl@sss.pgh.pa.us 173 :UBC 0 : default:
174 [ # # ]: 0 : ereport(ERROR,
175 : : (errcode(ERRCODE_SYNTAX_ERROR),
176 : : errmsg("%s requires an integer value",
177 : : def->defname)));
178 : : }
179 : : return 0; /* keep compiler quiet */
180 : : }
181 : :
182 : : /*
183 : : * Extract an int64 value from a DefElem.
184 : : */
185 : : int64
7998 tgl@sss.pgh.pa.us 186 :CBC 375 : defGetInt64(DefElem *def)
187 : : {
188 [ - + ]: 375 : if (def->arg == NULL)
7574 tgl@sss.pgh.pa.us 189 [ # # ]:UBC 0 : ereport(ERROR,
190 : : (errcode(ERRCODE_SYNTAX_ERROR),
191 : : errmsg("%s requires a numeric value",
192 : : def->defname)));
7998 tgl@sss.pgh.pa.us 193 [ + + - ]:CBC 375 : switch (nodeTag(def->arg))
194 : : {
195 : 359 : case T_Integer:
196 : 359 : return (int64) intVal(def->arg);
197 : 16 : case T_Float:
198 : :
199 : : /*
200 : : * Values too large for int4 will be represented as Float
201 : : * constants by the lexer. Accept these if they are valid int8
202 : : * strings.
203 : : */
204 : 16 : return DatumGetInt64(DirectFunctionCall1(int8in,
205 : : CStringGetDatum(castNode(Float, def->arg)->fval)));
7998 tgl@sss.pgh.pa.us 206 :UBC 0 : default:
7574 207 [ # # ]: 0 : ereport(ERROR,
208 : : (errcode(ERRCODE_SYNTAX_ERROR),
209 : : errmsg("%s requires a numeric value",
210 : : def->defname)));
211 : : }
212 : : return 0; /* keep compiler quiet */
213 : : }
214 : :
215 : : /*
216 : : * Extract an OID value from a DefElem.
217 : : */
218 : : Oid
527 tgl@sss.pgh.pa.us 219 :CBC 89 : defGetObjectId(DefElem *def)
220 : : {
221 [ - + ]: 89 : if (def->arg == NULL)
527 tgl@sss.pgh.pa.us 222 [ # # ]:UBC 0 : ereport(ERROR,
223 : : (errcode(ERRCODE_SYNTAX_ERROR),
224 : : errmsg("%s requires a numeric value",
225 : : def->defname)));
527 tgl@sss.pgh.pa.us 226 [ + - - ]:CBC 89 : switch (nodeTag(def->arg))
227 : : {
228 : 89 : case T_Integer:
229 : 89 : return (Oid) intVal(def->arg);
527 tgl@sss.pgh.pa.us 230 :UBC 0 : case T_Float:
231 : :
232 : : /*
233 : : * Values too large for int4 will be represented as Float
234 : : * constants by the lexer. Accept these if they are valid OID
235 : : * strings.
236 : : */
237 : 0 : return DatumGetObjectId(DirectFunctionCall1(oidin,
238 : : CStringGetDatum(castNode(Float, def->arg)->fval)));
239 : 0 : default:
240 [ # # ]: 0 : ereport(ERROR,
241 : : (errcode(ERRCODE_SYNTAX_ERROR),
242 : : errmsg("%s requires a numeric value",
243 : : def->defname)));
244 : : }
245 : : return 0; /* keep compiler quiet */
246 : : }
247 : :
248 : : /*
249 : : * Extract a possibly-qualified name (as a List of Strings) from a DefElem.
250 : : */
251 : : List *
8041 tgl@sss.pgh.pa.us 252 :CBC 7242 : defGetQualifiedName(DefElem *def)
253 : : {
254 [ - + ]: 7242 : if (def->arg == NULL)
7574 tgl@sss.pgh.pa.us 255 [ # # ]:UBC 0 : ereport(ERROR,
256 : : (errcode(ERRCODE_SYNTAX_ERROR),
257 : : errmsg("%s requires a parameter",
258 : : def->defname)));
8041 tgl@sss.pgh.pa.us 259 [ + + + - ]:CBC 7242 : switch (nodeTag(def->arg))
260 : : {
261 : 4643 : case T_TypeName:
262 : 7242 : return ((TypeName *) def->arg)->names;
7918 263 : 1300 : case T_List:
264 : 1300 : return (List *) def->arg;
8041 265 : 1299 : case T_String:
266 : : /* Allow quoted name for backwards compatibility */
7263 neilc@samurai.com 267 : 1299 : return list_make1(def->arg);
8041 tgl@sss.pgh.pa.us 268 :UBC 0 : default:
7574 269 [ # # ]: 0 : ereport(ERROR,
270 : : (errcode(ERRCODE_SYNTAX_ERROR),
271 : : errmsg("argument of %s must be a name",
272 : : def->defname)));
273 : : }
274 : : return NIL; /* keep compiler quiet */
275 : : }
276 : :
277 : : /*
278 : : * Extract a TypeName from a DefElem.
279 : : *
280 : : * Note: we do not accept a List arg here, because the parser will only
281 : : * return a bare List when the name looks like an operator name.
282 : : */
283 : : TypeName *
8052 tgl@sss.pgh.pa.us 284 :CBC 2956 : defGetTypeName(DefElem *def)
285 : : {
286 [ - + ]: 2956 : if (def->arg == NULL)
7574 tgl@sss.pgh.pa.us 287 [ # # ]:UBC 0 : ereport(ERROR,
288 : : (errcode(ERRCODE_SYNTAX_ERROR),
289 : : errmsg("%s requires a parameter",
290 : : def->defname)));
8052 tgl@sss.pgh.pa.us 291 [ + + - ]:CBC 2956 : switch (nodeTag(def->arg))
292 : : {
293 : 2953 : case T_TypeName:
294 : 2956 : return (TypeName *) def->arg;
295 : 3 : case T_String:
296 : : /* Allow quoted typename for backwards compatibility */
6606 297 : 3 : return makeTypeNameFromNameList(list_make1(def->arg));
8052 tgl@sss.pgh.pa.us 298 :UBC 0 : default:
7574 299 [ # # ]: 0 : ereport(ERROR,
300 : : (errcode(ERRCODE_SYNTAX_ERROR),
301 : : errmsg("argument of %s must be a type name",
302 : : def->defname)));
303 : : }
304 : : return NULL; /* keep compiler quiet */
305 : : }
306 : :
307 : : /*
308 : : * Extract a type length indicator (either absolute bytes, or
309 : : * -1 for "variable") from a DefElem.
310 : : */
311 : : int
9715 bruce@momjian.us 312 :CBC 65 : defGetTypeLength(DefElem *def)
313 : : {
8590 tgl@sss.pgh.pa.us 314 [ - + ]: 65 : if (def->arg == NULL)
7574 tgl@sss.pgh.pa.us 315 [ # # ]:UBC 0 : ereport(ERROR,
316 : : (errcode(ERRCODE_SYNTAX_ERROR),
317 : : errmsg("%s requires a parameter",
318 : : def->defname)));
8590 tgl@sss.pgh.pa.us 319 [ + - - + :CBC 65 : switch (nodeTag(def->arg))
- - ]
320 : : {
321 : 50 : case T_Integer:
322 : 50 : return intVal(def->arg);
8590 tgl@sss.pgh.pa.us 323 :UBC 0 : case T_Float:
7574 324 [ # # ]: 0 : ereport(ERROR,
325 : : (errcode(ERRCODE_SYNTAX_ERROR),
326 : : errmsg("%s requires an integer value",
327 : : def->defname)));
328 : : break;
8590 329 : 0 : case T_String:
7282 330 [ # # ]: 0 : if (pg_strcasecmp(strVal(def->arg), "variable") == 0)
8590 331 : 0 : return -1; /* variable length */
332 : 0 : break;
8590 tgl@sss.pgh.pa.us 333 :CBC 15 : case T_TypeName:
334 : : /* cope if grammar chooses to believe "variable" is a typename */
7282 335 [ + - ]: 15 : if (pg_strcasecmp(TypeNameToString((TypeName *) def->arg),
336 : : "variable") == 0)
8590 337 : 15 : return -1; /* variable length */
8590 tgl@sss.pgh.pa.us 338 :UBC 0 : break;
7918 339 : 0 : case T_List:
340 : : /* must be an operator name */
341 : 0 : break;
8590 342 : 0 : default:
7574 343 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
344 : : }
345 [ # # ]: 0 : ereport(ERROR,
346 : : (errcode(ERRCODE_SYNTAX_ERROR),
347 : : errmsg("invalid argument for %s: \"%s\"",
348 : : def->defname, defGetString(def))));
349 : : return 0; /* keep compiler quiet */
350 : : }
351 : :
352 : : /*
353 : : * Extract a list of string values (otherwise uninterpreted) from a DefElem.
354 : : */
355 : : List *
2642 peter_e@gmx.net 356 : 0 : defGetStringList(DefElem *def)
357 : : {
358 : : ListCell *cell;
359 : :
360 [ # # ]: 0 : if (def->arg == NULL)
361 [ # # ]: 0 : ereport(ERROR,
362 : : (errcode(ERRCODE_SYNTAX_ERROR),
363 : : errmsg("%s requires a parameter",
364 : : def->defname)));
365 [ # # ]: 0 : if (nodeTag(def->arg) != T_List)
366 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
367 : :
2524 bruce@momjian.us 368 [ # # # # : 0 : foreach(cell, (List *) def->arg)
# # ]
369 : : {
2642 peter_e@gmx.net 370 : 0 : Node *str = (Node *) lfirst(cell);
371 : :
372 [ # # ]: 0 : if (!IsA(str, String))
373 [ # # ]: 0 : elog(ERROR, "unexpected node type in name list: %d",
374 : : (int) nodeTag(str));
375 : : }
376 : :
377 : 0 : return (List *) def->arg;
378 : : }
379 : :
380 : : /*
381 : : * Raise an error about a conflicting DefElem.
382 : : */
383 : : void
1004 dean.a.rasheed@gmail 384 :CBC 75 : errorConflictingDefElem(DefElem *defel, ParseState *pstate)
385 : : {
386 [ + - ]: 75 : ereport(ERROR,
387 : : errcode(ERRCODE_SYNTAX_ERROR),
388 : : errmsg("conflicting or redundant options"),
389 : : parser_errposition(pstate, defel->location));
390 : : }
|