]> granicus.if.org Git - postgresql/blobdiff - src/backend/parser/parse_node.c
Update copyright for 2016
[postgresql] / src / backend / parser / parse_node.c
index 6aaeae76b0a68b4988a15524b687ff53f4a50011..62d2f7105fb61ad40ea001da3a7cab0cbd436581 100644 (file)
@@ -3,7 +3,7 @@
  * parse_node.c
  *       various routines that make nodes for querytrees
  *
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -15,6 +15,7 @@
 #include "postgres.h"
 
 #include "access/heapam.h"
+#include "access/htup_details.h"
 #include "catalog/pg_type.h"
 #include "mb/pg_wchar.h"
 #include "nodes/makefuncs.h"
@@ -98,8 +99,8 @@ free_parsestate(ParseState *pstate)
  * is a dummy (always 0, in fact).
  *
  * The locations stored in raw parsetrees are byte offsets into the source
- * string.     We have to convert them to 1-based character indexes for reporting
- * to clients. (We do things this way to avoid unnecessary overhead in the
+ * string.  We have to convert them to 1-based character indexes for reporting
+ * to clients.  (We do things this way to avoid unnecessary overhead in the
  * normal non-error case: computing character indexes would be much more
  * expensive than storing token offsets.)
  */
@@ -128,7 +129,7 @@ parser_errposition(ParseState *pstate, int location)
  * Sometimes the parser calls functions that aren't part of the parser
  * subsystem and can't reasonably be passed a ParseState; yet we would
  * like any errors thrown in those functions to be tagged with a parse
- * error location.     Use this function to set up an error context stack
+ * error location.  Use this function to set up an error context stack
  * entry that will accomplish that.  Usage pattern:
  *
  *             declare a local variable "ParseCallbackState pcbstate"
@@ -144,10 +145,10 @@ setup_parser_errposition_callback(ParseCallbackState *pcbstate,
        /* Setup error traceback support for ereport() */
        pcbstate->pstate = pstate;
        pcbstate->location = location;
-       pcbstate->errcontext.callback = pcb_error_callback;
-       pcbstate->errcontext.arg = (void *) pcbstate;
-       pcbstate->errcontext.previous = error_context_stack;
-       error_context_stack = &pcbstate->errcontext;
+       pcbstate->errcallback.callback = pcb_error_callback;
+       pcbstate->errcallback.arg = (void *) pcbstate;
+       pcbstate->errcallback.previous = error_context_stack;
+       error_context_stack = &pcbstate->errcallback;
 }
 
 /*
@@ -157,7 +158,7 @@ void
 cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
 {
        /* Pop the error context stack */
-       error_context_stack = pcbstate->errcontext.previous;
+       error_context_stack = pcbstate->errcallback.previous;
 }
 
 /*
@@ -220,11 +221,23 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod)
         * If the input is a domain, smash to base type, and extract the actual
         * typmod to be applied to the base type.  Subscripting a domain is an
         * operation that necessarily works on the base array type, not the domain
-        * itself.      (Note that we provide no method whereby the creator of a
+        * itself.  (Note that we provide no method whereby the creator of a
         * domain over an array type could hide its ability to be subscripted.)
         */
        *arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod);
 
+       /*
+        * We treat int2vector and oidvector as though they were domains over
+        * int2[] and oid[].  This is needed because array slicing could create an
+        * array that doesn't satisfy the dimensionality constraints of the
+        * xxxvector type; so we want the result of a slice operation to be
+        * considered to be of the more general type.
+        */
+       if (*arrayType == INT2VECTOROID)
+               *arrayType = INT2ARRAYOID;
+       else if (*arrayType == OIDVECTOROID)
+               *arrayType = OIDARRAYOID;
+
        /* Get the type tuple for the array */
        type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType));
        if (!HeapTupleIsValid(type_tuple_array))
@@ -256,12 +269,13 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod)
  *
  * In an array assignment, we are given a destination array value plus a
  * source value that is to be assigned to a single element or a slice of
- * that array. We produce an expression that represents the new array value
+ * that array.  We produce an expression that represents the new array value
  * with the source data inserted into the right part of the array.
  *
  * For both cases, if the source array is of a domain-over-array type,
  * the result is of the base array type or its element type; essentially,
  * we must fold a domain to its base type before applying subscripting.
+ * (Note that int2vector and oidvector are treated as domains here.)
  *
  * pstate              Parse state
  * arrayBase   Already-transformed expression for the array as a whole
@@ -297,18 +311,18 @@ transformArraySubscripts(ParseState *pstate,
                elementType = transformArrayType(&arrayType, &arrayTypMod);
 
        /*
-        * A list containing only single subscripts refers to a single array
-        * element.  If any of the items are double subscripts (lower:upper), then
-        * the subscript expression means an array slice operation. In this case,
-        * we supply a default lower bound of 1 for any items that contain only a
-        * single subscript.  We have to prescan the indirection list to see if
-        * there are any double subscripts.
+        * A list containing only simple subscripts refers to a single array
+        * element.  If any of the items are slice specifiers (lower:upper), then
+        * the subscript expression means an array slice operation.  In this case,
+        * we convert any non-slice items to slices by treating the single
+        * subscript as the upper bound and supplying an assumed lower bound of 1.
+        * We have to prescan the list to see if there are any slice items.
         */
        foreach(idx, indirection)
        {
                A_Indices  *ai = (A_Indices *) lfirst(idx);
 
-               if (ai->lidx != NULL)
+               if (ai->is_slice)
                {
                        isSlice = true;
                        break;
@@ -342,7 +356,7 @@ transformArraySubscripts(ParseState *pstate,
                                                         errmsg("array subscript must have type integer"),
                                                parser_errposition(pstate, exprLocation(ai->lidx))));
                        }
-                       else
+                       else if (!ai->is_slice)
                        {
                                /* Make a constant 1 */
                                subexpr = (Node *) makeConst(INT4OID,
@@ -353,21 +367,38 @@ transformArraySubscripts(ParseState *pstate,
                                                                                         false,
                                                                                         true);         /* pass by value */
                        }
+                       else
+                       {
+                               /* Slice with omitted lower bound, put NULL into the list */
+                               subexpr = NULL;
+                       }
                        lowerIndexpr = lappend(lowerIndexpr, subexpr);
                }
-               subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
-               /* If it's not int4 already, try to coerce */
-               subexpr = coerce_to_target_type(pstate,
-                                                                               subexpr, exprType(subexpr),
-                                                                               INT4OID, -1,
-                                                                               COERCION_ASSIGNMENT,
-                                                                               COERCE_IMPLICIT_CAST,
-                                                                               -1);
-               if (subexpr == NULL)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
-                                        errmsg("array subscript must have type integer"),
-                                        parser_errposition(pstate, exprLocation(ai->uidx))));
+               else
+                       Assert(ai->lidx == NULL && !ai->is_slice);
+
+               if (ai->uidx)
+               {
+                       subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
+                       /* If it's not int4 already, try to coerce */
+                       subexpr = coerce_to_target_type(pstate,
+                                                                                       subexpr, exprType(subexpr),
+                                                                                       INT4OID, -1,
+                                                                                       COERCION_ASSIGNMENT,
+                                                                                       COERCE_IMPLICIT_CAST,
+                                                                                       -1);
+                       if (subexpr == NULL)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                                errmsg("array subscript must have type integer"),
+                                                parser_errposition(pstate, exprLocation(ai->uidx))));
+               }
+               else
+               {
+                       /* Slice with omitted upper bound, put NULL into the list */
+                       Assert(isSlice && ai->is_slice);
+                       subexpr = NULL;
+               }
                upperIndexpr = lappend(upperIndexpr, subexpr);
        }