Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * parse_node.c
4 : : * various routines that make nodes for querytrees
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/parser/parse_node.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "access/htup_details.h"
18 : : #include "access/table.h"
19 : : #include "catalog/pg_type.h"
20 : : #include "mb/pg_wchar.h"
21 : : #include "nodes/makefuncs.h"
22 : : #include "nodes/miscnodes.h"
23 : : #include "nodes/nodeFuncs.h"
24 : : #include "nodes/subscripting.h"
25 : : #include "parser/parse_node.h"
26 : : #include "utils/builtins.h"
27 : : #include "utils/lsyscache.h"
28 : :
29 : : static void pcb_error_callback(void *arg);
30 : :
31 : :
32 : : /*
33 : : * make_parsestate
34 : : * Allocate and initialize a new ParseState.
35 : : *
36 : : * Caller should eventually release the ParseState via free_parsestate().
37 : : */
38 : : ParseState *
9582 bruce@momjian.us 39 :CBC 658408 : make_parsestate(ParseState *parentParseState)
40 : : {
41 : : ParseState *pstate;
42 : :
7823 43 : 658408 : pstate = palloc0(sizeof(ParseState));
44 : :
9582 45 : 658408 : pstate->parentParseState = parentParseState;
46 : :
47 : : /* Fill in fields that don't start at null/false/zero */
7656 tgl@sss.pgh.pa.us 48 : 658408 : pstate->p_next_resno = 1;
2636 49 : 658408 : pstate->p_resolve_unknowns = true;
50 : :
7656 51 [ + + ]: 658408 : if (parentParseState)
52 : : {
6606 53 : 42165 : pstate->p_sourcetext = parentParseState->p_sourcetext;
54 : : /* all hooks are copied from parent */
5279 55 : 42165 : pstate->p_pre_columnref_hook = parentParseState->p_pre_columnref_hook;
56 : 42165 : pstate->p_post_columnref_hook = parentParseState->p_post_columnref_hook;
57 : 42165 : pstate->p_paramref_hook = parentParseState->p_paramref_hook;
58 : 42165 : pstate->p_coerce_param_hook = parentParseState->p_coerce_param_hook;
59 : 42165 : pstate->p_ref_hook_state = parentParseState->p_ref_hook_state;
60 : : /* query environment stays in context for the whole parse analysis */
2571 kgrittn@postgresql.o 61 : 42165 : pstate->p_queryEnv = parentParseState->p_queryEnv;
62 : : }
63 : :
9357 bruce@momjian.us 64 : 658408 : return pstate;
65 : : }
66 : :
67 : : /*
68 : : * free_parsestate
69 : : * Release a ParseState and any subsidiary resources.
70 : : */
71 : : void
6140 tgl@sss.pgh.pa.us 72 : 604017 : free_parsestate(ParseState *pstate)
73 : : {
74 : : /*
75 : : * Check that we did not produce too many resnos; at the very least we
76 : : * cannot allow more than 2^16, since that would exceed the range of a
77 : : * AttrNumber. It seems safest to use MaxTupleAttributeNumber.
78 : : */
79 [ - + ]: 604017 : if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber)
6140 tgl@sss.pgh.pa.us 80 [ # # ]:UBC 0 : ereport(ERROR,
81 : : (errcode(ERRCODE_TOO_MANY_COLUMNS),
82 : : errmsg("target lists can have at most %d entries",
83 : : MaxTupleAttributeNumber)));
84 : :
6140 tgl@sss.pgh.pa.us 85 [ + + ]:CBC 604017 : if (pstate->p_target_relation != NULL)
1910 andres@anarazel.de 86 : 43703 : table_close(pstate->p_target_relation, NoLock);
87 : :
6140 tgl@sss.pgh.pa.us 88 : 604017 : pfree(pstate);
89 : 604017 : }
90 : :
91 : :
92 : : /*
93 : : * parser_errposition
94 : : * Report a parse-analysis-time cursor position, if possible.
95 : : *
96 : : * This is expected to be used within an ereport() call. The return value
97 : : * is a dummy (always 0, in fact).
98 : : *
99 : : * The locations stored in raw parsetrees are byte offsets into the source
100 : : * string. We have to convert them to 1-based character indexes for reporting
101 : : * to clients. (We do things this way to avoid unnecessary overhead in the
102 : : * normal non-error case: computing character indexes would be much more
103 : : * expensive than storing token offsets.)
104 : : */
105 : : int
6606 106 : 4351 : parser_errposition(ParseState *pstate, int location)
107 : : {
108 : : int pos;
109 : :
110 : : /* No-op if location was not provided */
111 [ + + ]: 4351 : if (location < 0)
1481 112 : 45 : return 0;
113 : : /* Can't do anything if source text is not available */
6606 114 [ + + + + ]: 4306 : if (pstate == NULL || pstate->p_sourcetext == NULL)
1481 115 : 69 : return 0;
116 : : /* Convert offset to character number */
6606 117 : 4237 : pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1;
118 : : /* And pass it to the ereport mechanism */
1481 119 : 4237 : return errposition(pos);
120 : : }
121 : :
122 : :
123 : : /*
124 : : * setup_parser_errposition_callback
125 : : * Arrange for non-parser errors to report an error position
126 : : *
127 : : * Sometimes the parser calls functions that aren't part of the parser
128 : : * subsystem and can't reasonably be passed a ParseState; yet we would
129 : : * like any errors thrown in those functions to be tagged with a parse
130 : : * error location. Use this function to set up an error context stack
131 : : * entry that will accomplish that. Usage pattern:
132 : : *
133 : : * declare a local variable "ParseCallbackState pcbstate"
134 : : * ...
135 : : * setup_parser_errposition_callback(&pcbstate, pstate, location);
136 : : * call function that might throw error;
137 : : * cancel_parser_errposition_callback(&pcbstate);
138 : : */
139 : : void
5704 140 : 912955 : setup_parser_errposition_callback(ParseCallbackState *pcbstate,
141 : : ParseState *pstate, int location)
142 : : {
143 : : /* Setup error traceback support for ereport() */
144 : 912955 : pcbstate->pstate = pstate;
145 : 912955 : pcbstate->location = location;
4171 heikki.linnakangas@i 146 : 912955 : pcbstate->errcallback.callback = pcb_error_callback;
147 : 912955 : pcbstate->errcallback.arg = (void *) pcbstate;
148 : 912955 : pcbstate->errcallback.previous = error_context_stack;
149 : 912955 : error_context_stack = &pcbstate->errcallback;
5704 tgl@sss.pgh.pa.us 150 : 912955 : }
151 : :
152 : : /*
153 : : * Cancel a previously-set-up errposition callback.
154 : : */
155 : : void
156 : 910537 : cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
157 : : {
158 : : /* Pop the error context stack */
4171 heikki.linnakangas@i 159 : 910537 : error_context_stack = pcbstate->errcallback.previous;
5704 tgl@sss.pgh.pa.us 160 : 910537 : }
161 : :
162 : : /*
163 : : * Error context callback for inserting parser error location.
164 : : *
165 : : * Note that this will be called for *any* error occurring while the
166 : : * callback is installed. We avoid inserting an irrelevant error location
167 : : * if the error is a query cancel --- are there any other important cases?
168 : : */
169 : : static void
170 : 2428 : pcb_error_callback(void *arg)
171 : : {
172 : 2428 : ParseCallbackState *pcbstate = (ParseCallbackState *) arg;
173 : :
174 [ + - ]: 2428 : if (geterrcode() != ERRCODE_QUERY_CANCELED)
175 : 2428 : (void) parser_errposition(pcbstate->pstate, pcbstate->location);
176 : 2428 : }
177 : :
178 : :
179 : : /*
180 : : * transformContainerType()
181 : : * Identify the actual container type for a subscripting operation.
182 : : *
183 : : * containerType/containerTypmod are modified if necessary to identify
184 : : * the actual container type and typmod. This mainly involves smashing
185 : : * any domain to its base type, but there are some special considerations.
186 : : * Note that caller still needs to check if the result type is a container.
187 : : */
188 : : void
1899 alvherre@alvh.no-ip. 189 : 5825 : transformContainerType(Oid *containerType, int32 *containerTypmod)
190 : : {
191 : : /*
192 : : * If the input is a domain, smash to base type, and extract the actual
193 : : * typmod to be applied to the base type. Subscripting a domain is an
194 : : * operation that necessarily works on the base container type, not the
195 : : * domain itself. (Note that we provide no method whereby the creator of a
196 : : * domain over a container type could hide its ability to be subscripted.)
197 : : */
198 : 5825 : *containerType = getBaseTypeAndTypmod(*containerType, containerTypmod);
199 : :
200 : : /*
201 : : * We treat int2vector and oidvector as though they were domains over
202 : : * int2[] and oid[]. This is needed because array slicing could create an
203 : : * array that doesn't satisfy the dimensionality constraints of the
204 : : * xxxvector type; so we want the result of a slice operation to be
205 : : * considered to be of the more general type.
206 : : */
207 [ + + ]: 5825 : if (*containerType == INT2VECTOROID)
208 : 1603 : *containerType = INT2ARRAYOID;
209 [ + + ]: 4222 : else if (*containerType == OIDVECTOROID)
210 : 411 : *containerType = OIDARRAYOID;
7249 tgl@sss.pgh.pa.us 211 : 5825 : }
212 : :
213 : : /*
214 : : * transformContainerSubscripts()
215 : : * Transform container (array, etc) subscripting. This is used for both
216 : : * container fetch and container assignment.
217 : : *
218 : : * In a container fetch, we are given a source container value and we produce
219 : : * an expression that represents the result of extracting a single container
220 : : * element or a container slice.
221 : : *
222 : : * Container assignments are treated basically the same as container fetches
223 : : * here. The caller will modify the result node to insert the source value
224 : : * that is to be assigned to the element or slice that a fetch would have
225 : : * retrieved. The execution result will be a new container value with
226 : : * the source value inserted into the right part of the container.
227 : : *
228 : : * For both cases, if the source is of a domain-over-container type, the
229 : : * result is the same as if it had been of the container type; essentially,
230 : : * we must fold a domain to its base type before applying subscripting.
231 : : * (Note that int2vector and oidvector are treated as domains here.)
232 : : *
233 : : * pstate Parse state
234 : : * containerBase Already-transformed expression for the container as a whole
235 : : * containerType OID of container's datatype (should match type of
236 : : * containerBase, or be the base type of containerBase's
237 : : * domain type)
238 : : * containerTypMod typmod for the container
239 : : * indirection Untransformed list of subscripts (must not be NIL)
240 : : * isAssignment True if this will become a container assignment.
241 : : */
242 : : SubscriptingRef *
1899 alvherre@alvh.no-ip. 243 : 5825 : transformContainerSubscripts(ParseState *pstate,
244 : : Node *containerBase,
245 : : Oid containerType,
246 : : int32 containerTypMod,
247 : : List *indirection,
248 : : bool isAssignment)
249 : : {
250 : : SubscriptingRef *sbsref;
251 : : const SubscriptRoutines *sbsroutines;
252 : : Oid elementType;
7249 tgl@sss.pgh.pa.us 253 : 5825 : bool isSlice = false;
254 : : ListCell *idx;
255 : :
256 : : /*
257 : : * Determine the actual container type, smashing any domain. In the
258 : : * assignment case the caller already did this, since it also needs to
259 : : * know the actual container type.
260 : : */
1222 261 [ + + ]: 5825 : if (!isAssignment)
262 : 4941 : transformContainerType(&containerType, &containerTypMod);
263 : :
264 : : /*
265 : : * Verify that the container type is subscriptable, and get its support
266 : : * functions and typelem.
267 : : */
268 : 5825 : sbsroutines = getSubscriptingRoutines(containerType, &elementType);
1220 269 [ + + ]: 5825 : if (!sbsroutines)
270 [ + - ]: 5 : ereport(ERROR,
271 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
272 : : errmsg("cannot subscript type %s because it does not support subscripting",
273 : : format_type_be(containerType)),
274 : : parser_errposition(pstate, exprLocation(containerBase))));
275 : :
276 : : /*
277 : : * Detect whether any of the indirection items are slice specifiers.
278 : : *
279 : : * A list containing only simple subscripts refers to a single container
280 : : * element. If any of the items are slice specifiers (lower:upper), then
281 : : * the subscript expression means a container slice operation.
282 : : */
7249 283 [ + - + + : 11655 : foreach(idx, indirection)
+ + ]
284 : : {
1222 285 : 6059 : A_Indices *ai = lfirst_node(A_Indices, idx);
286 : :
3036 287 [ + + ]: 6059 : if (ai->is_slice)
288 : : {
7249 289 : 224 : isSlice = true;
290 : 224 : break;
291 : : }
292 : : }
293 : :
294 : : /*
295 : : * Ready to build the SubscriptingRef node.
296 : : */
1222 297 : 5820 : sbsref = makeNode(SubscriptingRef);
298 : :
1899 alvherre@alvh.no-ip. 299 : 5820 : sbsref->refcontainertype = containerType;
300 : 5820 : sbsref->refelemtype = elementType;
301 : : /* refrestype is to be set by container-specific logic */
302 : 5820 : sbsref->reftypmod = containerTypMod;
303 : : /* refcollid will be set by parse_collate.c */
304 : : /* refupperindexpr, reflowerindexpr are to be set by container logic */
305 : 5820 : sbsref->refexpr = (Expr *) containerBase;
1222 tgl@sss.pgh.pa.us 306 : 5820 : sbsref->refassgnexpr = NULL; /* caller will fill if it's an assignment */
307 : :
308 : : /*
309 : : * Call the container-type-specific logic to transform the subscripts and
310 : : * determine the subscripting result type.
311 : : */
312 : 5820 : sbsroutines->transform(sbsref, indirection, pstate,
313 : : isSlice, isAssignment);
314 : :
315 : : /*
316 : : * Verify we got a valid type (this defends, for example, against someone
317 : : * using array_subscript_handler as typsubscript without setting typelem).
318 : : */
319 [ - + ]: 5797 : if (!OidIsValid(sbsref->refrestype))
1222 tgl@sss.pgh.pa.us 320 [ # # ]:UBC 0 : ereport(ERROR,
321 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
322 : : errmsg("cannot subscript type %s because it does not support subscripting",
323 : : format_type_be(containerType))));
324 : :
1899 alvherre@alvh.no-ip. 325 :CBC 5797 : return sbsref;
326 : : }
327 : :
328 : : /*
329 : : * make_const
330 : : *
331 : : * Convert an A_Const node (as returned by the grammar) to a Const node
332 : : * of the "natural" type for the constant. Note that this routine is
333 : : * only used when there is no explicit cast for the constant, so we
334 : : * have to guess what type is wanted.
335 : : *
336 : : * For string literals we produce a constant of type UNKNOWN ---- whose
337 : : * representation is the same as cstring, but it indicates to later type
338 : : * resolution that we're not sure yet what type it should be considered.
339 : : * Explicit "NULL" constants are also typed as UNKNOWN.
340 : : *
341 : : * For integers and floats we produce int4, int8, or numeric depending
342 : : * on the value of the number. XXX We should produce int2 as well,
343 : : * but additional cleanup is needed before we can do that; there are
344 : : * too many examples that fail if we try.
345 : : */
346 : : Const *
948 peter@eisentraut.org 347 : 533461 : make_const(ParseState *pstate, A_Const *aconst)
348 : : {
349 : : Const *con;
350 : : Datum val;
351 : : Oid typeid;
352 : : int typelen;
353 : : bool typebyval;
354 : : ParseCallbackState pcbstate;
355 : :
356 [ + + ]: 533461 : if (aconst->isnull)
357 : : {
358 : : /* return a null const */
359 : 31673 : con = makeConst(UNKNOWNOID,
360 : : -1,
361 : : InvalidOid,
362 : : -2,
363 : : (Datum) 0,
364 : : true,
365 : : false);
366 : 31673 : con->location = aconst->location;
367 : 31673 : return con;
368 : : }
369 : :
370 [ + + + + : 501788 : switch (nodeTag(&aconst->val))
+ - ]
371 : : {
9715 bruce@momjian.us 372 : 186535 : case T_Integer:
821 peter@eisentraut.org 373 : 186535 : val = Int32GetDatum(intVal(&aconst->val));
374 : :
8931 tgl@sss.pgh.pa.us 375 : 186535 : typeid = INT4OID;
376 : 186535 : typelen = sizeof(int32);
377 : 186535 : typebyval = true;
9715 bruce@momjian.us 378 : 186535 : break;
379 : :
380 : 5238 : case T_Float:
381 : : {
382 : : /* could be an oversize integer as well as a float ... */
383 : :
435 dean.a.rasheed@gmail 384 : 5238 : ErrorSaveContext escontext = {T_ErrorSaveContext};
385 : : int64 val64;
386 : :
387 : 5238 : val64 = pg_strtoint64_safe(aconst->val.fval.fval, (Node *) &escontext);
388 [ + + ]: 5238 : if (!escontext.error_occurred)
389 : : {
390 : : /*
391 : : * It might actually fit in int32. Probably only INT_MIN
392 : : * can occur, but we'll code the test generally just to be
393 : : * sure.
394 : : */
703 tgl@sss.pgh.pa.us 395 : 520 : int32 val32 = (int32) val64;
396 : :
397 [ + + ]: 520 : if (val64 == (int64) val32)
398 : : {
399 : 75 : val = Int32GetDatum(val32);
400 : :
401 : 75 : typeid = INT4OID;
402 : 75 : typelen = sizeof(int32);
403 : 75 : typebyval = true;
404 : : }
405 : : else
406 : : {
407 : 445 : val = Int64GetDatum(val64);
408 : :
409 : 445 : typeid = INT8OID;
410 : 445 : typelen = sizeof(int64);
411 : 445 : typebyval = FLOAT8PASSBYVAL; /* int8 and float8 alike */
412 : : }
413 : : }
414 : : else
415 : : {
416 : : /* arrange to report location if numeric_in() fails */
417 : 4718 : setup_parser_errposition_callback(&pcbstate, pstate, aconst->location);
418 : 4718 : val = DirectFunctionCall3(numeric_in,
419 : : CStringGetDatum(aconst->val.fval.fval),
420 : : ObjectIdGetDatum(InvalidOid),
421 : : Int32GetDatum(-1));
422 : 4718 : cancel_parser_errposition_callback(&pcbstate);
423 : :
424 : 4718 : typeid = NUMERICOID;
425 : 4718 : typelen = -1; /* variable len */
426 : 4718 : typebyval = false;
427 : : }
428 : 5238 : break;
429 : : }
430 : :
821 peter@eisentraut.org 431 : 27158 : case T_Boolean:
432 : 27158 : val = BoolGetDatum(boolVal(&aconst->val));
433 : :
434 : 27158 : typeid = BOOLOID;
435 : 27158 : typelen = 1;
436 : 27158 : typebyval = true;
437 : 27158 : break;
438 : :
9715 bruce@momjian.us 439 : 280822 : case T_String:
440 : :
441 : : /*
442 : : * We assume here that UNKNOWN's internal representation is the
443 : : * same as CSTRING
444 : : */
821 peter@eisentraut.org 445 : 280822 : val = CStringGetDatum(strVal(&aconst->val));
446 : :
8204 bruce@momjian.us 447 : 280822 : typeid = UNKNOWNOID; /* will be coerced later */
6756 448 : 280822 : typelen = -2; /* cstring-style varwidth type */
8931 tgl@sss.pgh.pa.us 449 : 280822 : typebyval = false;
9715 bruce@momjian.us 450 : 280822 : break;
451 : :
8566 peter_e@gmx.net 452 : 2035 : case T_BitString:
453 : : /* arrange to report location if bit_in() fails */
948 peter@eisentraut.org 454 : 2035 : setup_parser_errposition_callback(&pcbstate, pstate, aconst->location);
8363 peter_e@gmx.net 455 : 2035 : val = DirectFunctionCall3(bit_in,
456 : : CStringGetDatum(aconst->val.bsval.bsval),
457 : : ObjectIdGetDatum(InvalidOid),
458 : : Int32GetDatum(-1));
5704 tgl@sss.pgh.pa.us 459 : 2023 : cancel_parser_errposition_callback(&pcbstate);
8363 peter_e@gmx.net 460 : 2023 : typeid = BITOID;
8566 461 : 2023 : typelen = -1;
462 : 2023 : typebyval = false;
463 : 2023 : break;
464 : :
7575 tgl@sss.pgh.pa.us 465 :UBC 0 : default:
948 peter@eisentraut.org 466 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(&aconst->val));
467 : : return NULL; /* keep compiler quiet */
468 : : }
469 : :
8931 tgl@sss.pgh.pa.us 470 :CBC 501776 : con = makeConst(typeid,
471 : : -1, /* typmod -1 is OK for all cases */
472 : : InvalidOid, /* all cases are uncollatable types */
473 : : typelen,
474 : : val,
475 : : false,
476 : : typebyval);
948 peter@eisentraut.org 477 : 501776 : con->location = aconst->location;
478 : :
9357 bruce@momjian.us 479 : 501776 : return con;
480 : : }
|