Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/parser/parse_node.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * parse_node.c
4
 *    various routines that make nodes for querytrees
5
 *
6
 * Portions Copyright (c) 1996-2025, 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 *
39
make_parsestate(ParseState *parentParseState)
40
348
{
41
348
  ParseState *pstate;
42
43
348
  pstate = palloc0(sizeof(ParseState));
44
45
348
  pstate->parentParseState = parentParseState;
46
47
  /* Fill in fields that don't start at null/false/zero */
48
348
  pstate->p_next_resno = 1;
49
348
  pstate->p_resolve_unknowns = true;
50
51
348
  if (parentParseState)
52
0
  {
53
0
    pstate->p_sourcetext = parentParseState->p_sourcetext;
54
    /* all hooks are copied from parent */
55
0
    pstate->p_pre_columnref_hook = parentParseState->p_pre_columnref_hook;
56
0
    pstate->p_post_columnref_hook = parentParseState->p_post_columnref_hook;
57
0
    pstate->p_paramref_hook = parentParseState->p_paramref_hook;
58
0
    pstate->p_coerce_param_hook = parentParseState->p_coerce_param_hook;
59
0
    pstate->p_ref_hook_state = parentParseState->p_ref_hook_state;
60
    /* query environment stays in context for the whole parse analysis */
61
0
    pstate->p_queryEnv = parentParseState->p_queryEnv;
62
0
  }
63
64
348
  return pstate;
65
348
}
66
67
/*
68
 * free_parsestate
69
 *    Release a ParseState and any subsidiary resources.
70
 */
71
void
72
free_parsestate(ParseState *pstate)
73
348
{
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
348
  if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber)
80
348
    ereport(ERROR,
81
348
        (errcode(ERRCODE_TOO_MANY_COLUMNS),
82
348
         errmsg("target lists can have at most %d entries",
83
348
            MaxTupleAttributeNumber)));
84
85
348
  if (pstate->p_target_relation != NULL)
86
0
    table_close(pstate->p_target_relation, NoLock);
87
88
348
  pfree(pstate);
89
348
}
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
106
parser_errposition(ParseState *pstate, int location)
107
0
{
108
0
  int     pos;
109
110
  /* No-op if location was not provided */
111
0
  if (location < 0)
112
0
    return 0;
113
  /* Can't do anything if source text is not available */
114
0
  if (pstate == NULL || pstate->p_sourcetext == NULL)
115
0
    return 0;
116
  /* Convert offset to character number */
117
0
  pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1;
118
  /* And pass it to the ereport mechanism */
119
0
  return errposition(pos);
120
0
}
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
140
setup_parser_errposition_callback(ParseCallbackState *pcbstate,
141
                  ParseState *pstate, int location)
142
0
{
143
  /* Setup error traceback support for ereport() */
144
0
  pcbstate->pstate = pstate;
145
0
  pcbstate->location = location;
146
0
  pcbstate->errcallback.callback = pcb_error_callback;
147
0
  pcbstate->errcallback.arg = pcbstate;
148
0
  pcbstate->errcallback.previous = error_context_stack;
149
0
  error_context_stack = &pcbstate->errcallback;
150
0
}
151
152
/*
153
 * Cancel a previously-set-up errposition callback.
154
 */
155
void
156
cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
157
0
{
158
  /* Pop the error context stack */
159
0
  error_context_stack = pcbstate->errcallback.previous;
160
0
}
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
pcb_error_callback(void *arg)
171
0
{
172
0
  ParseCallbackState *pcbstate = (ParseCallbackState *) arg;
173
174
0
  if (geterrcode() != ERRCODE_QUERY_CANCELED)
175
0
    (void) parser_errposition(pcbstate->pstate, pcbstate->location);
176
0
}
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
189
transformContainerType(Oid *containerType, int32 *containerTypmod)
190
0
{
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
0
  *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
0
  if (*containerType == INT2VECTOROID)
208
0
    *containerType = INT2ARRAYOID;
209
0
  else if (*containerType == OIDVECTOROID)
210
0
    *containerType = OIDARRAYOID;
211
0
}
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 *
243
transformContainerSubscripts(ParseState *pstate,
244
               Node *containerBase,
245
               Oid containerType,
246
               int32 containerTypMod,
247
               List *indirection,
248
               bool isAssignment)
249
0
{
250
0
  SubscriptingRef *sbsref;
251
0
  const SubscriptRoutines *sbsroutines;
252
0
  Oid     elementType;
253
0
  bool    isSlice = false;
254
0
  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
   */
261
0
  if (!isAssignment)
262
0
    transformContainerType(&containerType, &containerTypMod);
263
264
  /*
265
   * Verify that the container type is subscriptable, and get its support
266
   * functions and typelem.
267
   */
268
0
  sbsroutines = getSubscriptingRoutines(containerType, &elementType);
269
0
  if (!sbsroutines)
270
0
    ereport(ERROR,
271
0
        (errcode(ERRCODE_DATATYPE_MISMATCH),
272
0
         errmsg("cannot subscript type %s because it does not support subscripting",
273
0
            format_type_be(containerType)),
274
0
         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
   */
283
0
  foreach(idx, indirection)
284
0
  {
285
0
    A_Indices  *ai = lfirst_node(A_Indices, idx);
286
287
0
    if (ai->is_slice)
288
0
    {
289
0
      isSlice = true;
290
0
      break;
291
0
    }
292
0
  }
293
294
  /*
295
   * Ready to build the SubscriptingRef node.
296
   */
297
0
  sbsref = makeNode(SubscriptingRef);
298
299
0
  sbsref->refcontainertype = containerType;
300
0
  sbsref->refelemtype = elementType;
301
  /* refrestype is to be set by container-specific logic */
302
0
  sbsref->reftypmod = containerTypMod;
303
  /* refcollid will be set by parse_collate.c */
304
  /* refupperindexpr, reflowerindexpr are to be set by container logic */
305
0
  sbsref->refexpr = (Expr *) containerBase;
306
0
  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
0
  sbsroutines->transform(sbsref, indirection, pstate,
313
0
               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
0
  if (!OidIsValid(sbsref->refrestype))
320
0
    ereport(ERROR,
321
0
        (errcode(ERRCODE_DATATYPE_MISMATCH),
322
0
         errmsg("cannot subscript type %s because it does not support subscripting",
323
0
            format_type_be(containerType))));
324
325
0
  return sbsref;
326
0
}
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 *
347
make_const(ParseState *pstate, A_Const *aconst)
348
0
{
349
0
  Const    *con;
350
0
  Datum   val;
351
0
  Oid     typeid;
352
0
  int     typelen;
353
0
  bool    typebyval;
354
0
  ParseCallbackState pcbstate;
355
356
0
  if (aconst->isnull)
357
0
  {
358
    /* return a null const */
359
0
    con = makeConst(UNKNOWNOID,
360
0
            -1,
361
0
            InvalidOid,
362
0
            -2,
363
0
            (Datum) 0,
364
0
            true,
365
0
            false);
366
0
    con->location = aconst->location;
367
0
    return con;
368
0
  }
369
370
0
  switch (nodeTag(&aconst->val))
371
0
  {
372
0
    case T_Integer:
373
0
      val = Int32GetDatum(intVal(&aconst->val));
374
375
0
      typeid = INT4OID;
376
0
      typelen = sizeof(int32);
377
0
      typebyval = true;
378
0
      break;
379
380
0
    case T_Float:
381
0
      {
382
        /* could be an oversize integer as well as a float ... */
383
384
0
        ErrorSaveContext escontext = {T_ErrorSaveContext};
385
0
        int64   val64;
386
387
0
        val64 = pg_strtoint64_safe(aconst->val.fval.fval, (Node *) &escontext);
388
0
        if (!escontext.error_occurred)
389
0
        {
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
           */
395
0
          int32   val32 = (int32) val64;
396
397
0
          if (val64 == (int64) val32)
398
0
          {
399
0
            val = Int32GetDatum(val32);
400
401
0
            typeid = INT4OID;
402
0
            typelen = sizeof(int32);
403
0
            typebyval = true;
404
0
          }
405
0
          else
406
0
          {
407
0
            val = Int64GetDatum(val64);
408
409
0
            typeid = INT8OID;
410
0
            typelen = sizeof(int64);
411
0
            typebyval = true;
412
0
          }
413
0
        }
414
0
        else
415
0
        {
416
          /* arrange to report location if numeric_in() fails */
417
0
          setup_parser_errposition_callback(&pcbstate, pstate, aconst->location);
418
0
          val = DirectFunctionCall3(numeric_in,
419
0
                        CStringGetDatum(aconst->val.fval.fval),
420
0
                        ObjectIdGetDatum(InvalidOid),
421
0
                        Int32GetDatum(-1));
422
0
          cancel_parser_errposition_callback(&pcbstate);
423
424
0
          typeid = NUMERICOID;
425
0
          typelen = -1; /* variable len */
426
0
          typebyval = false;
427
0
        }
428
0
        break;
429
0
      }
430
431
0
    case T_Boolean:
432
0
      val = BoolGetDatum(boolVal(&aconst->val));
433
434
0
      typeid = BOOLOID;
435
0
      typelen = 1;
436
0
      typebyval = true;
437
0
      break;
438
439
0
    case T_String:
440
441
      /*
442
       * We assume here that UNKNOWN's internal representation is the
443
       * same as CSTRING
444
       */
445
0
      val = CStringGetDatum(strVal(&aconst->val));
446
447
0
      typeid = UNKNOWNOID; /* will be coerced later */
448
0
      typelen = -2;   /* cstring-style varwidth type */
449
0
      typebyval = false;
450
0
      break;
451
452
0
    case T_BitString:
453
      /* arrange to report location if bit_in() fails */
454
0
      setup_parser_errposition_callback(&pcbstate, pstate, aconst->location);
455
0
      val = DirectFunctionCall3(bit_in,
456
0
                    CStringGetDatum(aconst->val.bsval.bsval),
457
0
                    ObjectIdGetDatum(InvalidOid),
458
0
                    Int32GetDatum(-1));
459
0
      cancel_parser_errposition_callback(&pcbstate);
460
0
      typeid = BITOID;
461
0
      typelen = -1;
462
0
      typebyval = false;
463
0
      break;
464
465
0
    default:
466
0
      elog(ERROR, "unrecognized node type: %d", (int) nodeTag(&aconst->val));
467
0
      return NULL;   /* keep compiler quiet */
468
0
  }
469
470
0
  con = makeConst(typeid,
471
0
          -1,     /* typmod -1 is OK for all cases */
472
0
          InvalidOid, /* all cases are uncollatable types */
473
0
          typelen,
474
0
          val,
475
0
          false,
476
0
          typebyval);
477
0
  con->location = aconst->location;
478
479
0
  return con;
480
0
}