diff options
Diffstat (limited to 'src/backend/parser/parse_target.c')
-rw-r--r-- | src/backend/parser/parse_target.c | 127 |
1 files changed, 95 insertions, 32 deletions
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index e93c0afe915..c777484d45d 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -43,6 +43,16 @@ static Node *transformAssignmentIndirection(ParseState *pstate, ListCell *indirection, Node *rhs, int location); +static Node *transformAssignmentSubscripts(ParseState *pstate, + Node *basenode, + const char *targetName, + Oid targetTypeId, + int32 targetTypMod, + List *subscripts, + bool isSlice, + ListCell *next_indirection, + Node *rhs, + int location); static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref, bool targetlist); static List *ExpandAllTables(ParseState *pstate, int location); @@ -613,27 +623,17 @@ transformAssignmentIndirection(ParseState *pstate, /* process subscripts before this field selection */ if (subscripts) { - Oid elementTypeId = transformArrayType(targetTypeId); - Oid typeNeeded = isSlice ? targetTypeId : elementTypeId; - - /* recurse to create appropriate RHS for array assign */ - rhs = transformAssignmentIndirection(pstate, - NULL, + /* recurse, and then return because we're done */ + return transformAssignmentSubscripts(pstate, + basenode, targetName, - true, - typeNeeded, + targetTypeId, targetTypMod, + subscripts, + isSlice, i, rhs, location); - /* process subscripts */ - return (Node *) transformArraySubscripts(pstate, - basenode, - targetTypeId, - elementTypeId, - targetTypMod, - subscripts, - rhs); } /* No subscripts, so can process field selection here */ @@ -690,27 +690,17 @@ transformAssignmentIndirection(ParseState *pstate, /* process trailing subscripts, if any */ if (subscripts) { - Oid elementTypeId = transformArrayType(targetTypeId); - Oid typeNeeded = isSlice ? targetTypeId : elementTypeId; - - /* recurse to create appropriate RHS for array assign */ - rhs = transformAssignmentIndirection(pstate, - NULL, + /* recurse, and then return because we're done */ + return transformAssignmentSubscripts(pstate, + basenode, targetName, - true, - typeNeeded, + targetTypeId, targetTypMod, + subscripts, + isSlice, NULL, rhs, location); - /* process subscripts */ - return (Node *) transformArraySubscripts(pstate, - basenode, - targetTypeId, - elementTypeId, - targetTypMod, - subscripts, - rhs); } /* base case: just coerce RHS to match target type ID */ @@ -748,6 +738,79 @@ transformAssignmentIndirection(ParseState *pstate, return result; } +/* + * helper for transformAssignmentIndirection: process array assignment + */ +static Node * +transformAssignmentSubscripts(ParseState *pstate, + Node *basenode, + const char *targetName, + Oid targetTypeId, + int32 targetTypMod, + List *subscripts, + bool isSlice, + ListCell *next_indirection, + Node *rhs, + int location) +{ + Node *result; + Oid arrayType; + int32 arrayTypMod; + Oid elementTypeId; + Oid typeNeeded; + + Assert(subscripts != NIL); + + /* Identify the actual array type and element type involved */ + arrayType = targetTypeId; + arrayTypMod = targetTypMod; + elementTypeId = transformArrayType(&arrayType, &arrayTypMod); + + /* Identify type that RHS must provide */ + typeNeeded = isSlice ? arrayType : elementTypeId; + + /* recurse to create appropriate RHS for array assign */ + rhs = transformAssignmentIndirection(pstate, + NULL, + targetName, + true, + typeNeeded, + arrayTypMod, + next_indirection, + rhs, + location); + + /* process subscripts */ + result = (Node *) transformArraySubscripts(pstate, + basenode, + arrayType, + elementTypeId, + arrayTypMod, + subscripts, + rhs); + + /* If target was a domain over array, need to coerce up to the domain */ + if (arrayType != targetTypeId) + { + result = coerce_to_target_type(pstate, + result, exprType(result), + targetTypeId, targetTypMod, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + /* probably shouldn't fail, but check */ + if (result == NULL) + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast type %s to %s", + format_type_be(exprType(result)), + format_type_be(targetTypeId)), + parser_errposition(pstate, location))); + } + + return result; +} + /* * checkInsertTargets - |