* 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
*
*
#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"
* 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.)
*/
* 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"
/* 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;
}
/*
cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
{
/* Pop the error context stack */
- error_context_stack = pcbstate->errcontext.previous;
+ error_context_stack = pcbstate->errcallback.previous;
}
/*
* 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))
*
* 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
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;
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,
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);
}