summaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_node.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_node.c')
-rw-r--r--src/backend/parser/parse_node.c64
1 files changed, 47 insertions, 17 deletions
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 59f1245fd6..7b5c040cb4 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -3,12 +3,12 @@
* parse_node.c
* various routines that make nodes for querytrees
*
- * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.108 2010/02/14 18:42:15 rhaas Exp $
+ * src/backend/parser/parse_node.c
*
*-------------------------------------------------------------------------
*/
@@ -25,6 +25,7 @@
#include "parser/parse_relation.h"
#include "utils/builtins.h"
#include "utils/int8.h"
+#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/varbit.h"
@@ -188,29 +189,46 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
sublevels_up;
Oid vartypeid;
int32 type_mod;
+ Oid varcollid;
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
- get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod);
- result = makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
+ get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod, &varcollid);
+ result = makeVar(vnum, attrno, vartypeid, type_mod, varcollid, sublevels_up);
result->location = location;
return result;
}
/*
* transformArrayType()
- * Get the element type of an array type in preparation for subscripting
+ * Identify the types involved in a subscripting operation
+ *
+ * On entry, arrayType/arrayTypmod identify the type of the input value
+ * to be subscripted (which could be a domain type). These are modified
+ * if necessary to identify the actual array type and typmod, and the
+ * array's element type is returned. An error is thrown if the input isn't
+ * an array type.
*/
Oid
-transformArrayType(Oid arrayType)
+transformArrayType(Oid *arrayType, int32 *arrayTypmod)
{
+ Oid origArrayType = *arrayType;
Oid elementType;
HeapTuple type_tuple_array;
Form_pg_type type_struct_array;
+ /*
+ * 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
+ * domain over an array type could hide its ability to be subscripted.)
+ */
+ *arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod);
+
/* Get the type tuple for the array */
- type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayType));
+ type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType));
if (!HeapTupleIsValid(type_tuple_array))
- elog(ERROR, "cache lookup failed for type %u", arrayType);
+ elog(ERROR, "cache lookup failed for type %u", *arrayType);
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array);
/* needn't check typisdefined since this will fail anyway */
@@ -220,7 +238,7 @@ transformArrayType(Oid arrayType)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot subscript type %s because it is not an array",
- format_type_be(arrayType))));
+ format_type_be(origArrayType))));
ReleaseSysCache(type_tuple_array);
@@ -241,13 +259,17 @@ transformArrayType(Oid arrayType)
* 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.
+ *
* pstate Parse state
* arrayBase Already-transformed expression for the array as a whole
- * arrayType OID of array's datatype (should match type of arrayBase)
+ * arrayType OID of array's datatype (should match type of arrayBase,
+ * or be the base type of arrayBase's domain type)
* elementType OID of array's element type (fetch with transformArrayType,
* or pass InvalidOid to do it here)
- * elementTypMod typmod to be applied to array elements (if storing) or of
- * the source array (if fetching)
+ * arrayTypMod typmod for the array (which is also typmod for the elements)
* indirection Untransformed list of subscripts (must not be NIL)
* assignFrom NULL for array fetch, else transformed expression for source.
*/
@@ -256,7 +278,7 @@ transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
Oid elementType,
- int32 elementTypMod,
+ int32 arrayTypMod,
List *indirection,
Node *assignFrom)
{
@@ -266,9 +288,13 @@ transformArraySubscripts(ParseState *pstate,
ListCell *idx;
ArrayRef *aref;
- /* Caller may or may not have bothered to determine elementType */
+ /*
+ * Caller may or may not have bothered to determine elementType. Note
+ * that if the caller did do so, arrayType/arrayTypMod must be as modified
+ * by transformArrayType, ie, smash domain to base type.
+ */
if (!OidIsValid(elementType))
- elementType = transformArrayType(arrayType);
+ elementType = transformArrayType(&arrayType, &arrayTypMod);
/*
* A list containing only single subscripts refers to a single array
@@ -321,6 +347,7 @@ transformArraySubscripts(ParseState *pstate,
/* Make a constant 1 */
subexpr = (Node *) makeConst(INT4OID,
-1,
+ InvalidOid,
sizeof(int32),
Int32GetDatum(1),
false,
@@ -356,7 +383,7 @@ transformArraySubscripts(ParseState *pstate,
newFrom = coerce_to_target_type(pstate,
assignFrom, typesource,
- typeneeded, elementTypMod,
+ typeneeded, arrayTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
@@ -378,7 +405,8 @@ transformArraySubscripts(ParseState *pstate,
aref = makeNode(ArrayRef);
aref->refarraytype = arrayType;
aref->refelemtype = elementType;
- aref->reftypmod = elementTypMod;
+ aref->reftypmod = arrayTypMod;
+ /* refcollid will be set by parse_collate.c */
aref->refupperindexpr = upperIndexpr;
aref->reflowerindexpr = lowerIndexpr;
aref->refexpr = (Expr *) arrayBase;
@@ -499,6 +527,7 @@ make_const(ParseState *pstate, Value *value, int location)
/* return a null const */
con = makeConst(UNKNOWNOID,
-1,
+ InvalidOid,
-2,
(Datum) 0,
true,
@@ -513,6 +542,7 @@ make_const(ParseState *pstate, Value *value, int location)
con = makeConst(typeid,
-1, /* typmod -1 is OK for all cases */
+ InvalidOid, /* all cases are uncollatable types */
typelen,
val,
false,