LCOV - code coverage report
Current view: top level - src/backend/parser - parse_node.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 119 123 96.7 %
Date: 2021-12-04 22:09:09 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14