diff options
-rw-r--r-- | src/backend/catalog/dependency.c | 43 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 2 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 54 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 21 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 16 | ||||
-rw-r--r-- | src/backend/nodes/nodeFuncs.c | 45 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 24 | ||||
-rw-r--r-- | src/backend/nodes/readfuncs.c | 35 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 48 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 10 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 16 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 10 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 2 | ||||
-rw-r--r-- | src/backend/parser/parse_type.c | 2 | ||||
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 2 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 60 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/nodes/nodes.h | 3 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 11 | ||||
-rw-r--r-- | src/include/nodes/primnodes.h | 24 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 3 | ||||
-rw-r--r-- | src/test/regress/expected/collate.linux.utf8.out | 4 |
22 files changed, 298 insertions, 139 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index bce0e076837..9e2028a64ff 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -1357,6 +1357,9 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, * on the datatype, and OpExpr nodes depend on the operator which depends on * the datatype. However we do need a type dependency if there is no such * indirect dependency, as for example in Const and CoerceToDomain nodes. + * + * Similarly, we don't need to create dependencies on collations except where + * the collation is being freshly introduced to the expression. */ static bool find_expr_references_walker(Node *node, @@ -1425,7 +1428,15 @@ find_expr_references_walker(Node *node, /* A constant must depend on the constant's datatype */ add_object_address(OCLASS_TYPE, con->consttype, 0, context->addrs); - if (OidIsValid(con->constcollid)) + + /* + * We must also depend on the constant's collation: it could be + * different from the datatype's, if a CollateExpr was const-folded + * to a simple constant. However we can save work in the most common + * case where the collation is "default", since we know that's pinned. + */ + if (OidIsValid(con->constcollid) && + con->constcollid != DEFAULT_COLLATION_OID) add_object_address(OCLASS_COLLATION, con->constcollid, 0, context->addrs); @@ -1494,7 +1505,9 @@ find_expr_references_walker(Node *node, /* A parameter must depend on the parameter's datatype */ add_object_address(OCLASS_TYPE, param->paramtype, 0, context->addrs); - if (OidIsValid(param->paramcollation)) + /* and its collation, just as for Consts */ + if (OidIsValid(param->paramcollation) && + param->paramcollation != DEFAULT_COLLATION_OID) add_object_address(OCLASS_COLLATION, param->paramcollation, 0, context->addrs); } @@ -1567,13 +1580,6 @@ find_expr_references_walker(Node *node, add_object_address(OCLASS_TYPE, relab->resulttype, 0, context->addrs); } - else if (IsA(node, CollateClause)) - { - CollateClause *coll = (CollateClause *) node; - - add_object_address(OCLASS_COLLATION, coll->collOid, 0, - context->addrs); - } else if (IsA(node, CoerceViaIO)) { CoerceViaIO *iocoerce = (CoerceViaIO *) node; @@ -1601,6 +1607,13 @@ find_expr_references_walker(Node *node, add_object_address(OCLASS_TYPE, cvt->resulttype, 0, context->addrs); } + else if (IsA(node, CollateExpr)) + { + CollateExpr *coll = (CollateExpr *) node; + + add_object_address(OCLASS_COLLATION, coll->collOid, 0, + context->addrs); + } else if (IsA(node, RowExpr)) { RowExpr *rowexpr = (RowExpr *) node; @@ -1652,10 +1665,11 @@ find_expr_references_walker(Node *node, /* * Add whole-relation refs for each plain relation mentioned in the - * subquery's rtable, as well as datatype refs for any datatypes used - * as a RECORD function's output. (Note: query_tree_walker takes care - * of recursing into RTE_FUNCTION RTEs, subqueries, etc, so no need to - * do that here. But keep it from looking at join alias lists.) + * subquery's rtable, as well as refs for any datatypes and collations + * used in a RECORD function's output. (Note: query_tree_walker takes + * care of recursing into RTE_FUNCTION RTEs, subqueries, etc, so no + * need to do that here. But keep it from looking at join alias + * lists.) */ foreach(lc, query->rtable) { @@ -1678,7 +1692,8 @@ find_expr_references_walker(Node *node, { Oid collid = lfirst_oid(ct); - if (OidIsValid(collid)) + if (OidIsValid(collid) && + collid != DEFAULT_COLLATION_OID) add_object_address(OCLASS_COLLATION, collid, 0, context->addrs); } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 3513256b9a5..ee3bca17d17 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -831,7 +831,7 @@ DefineDomain(CreateDomainStmt *stmt) */ baseColl = baseType->typcollation; if (stmt->collClause) - domaincoll = get_collation_oid(stmt->collClause->collnames, false); + domaincoll = get_collation_oid(stmt->collClause->collname, false); else domaincoll = baseColl; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 2b5dd2dbf85..0faf52dfd79 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -120,6 +120,9 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalCollateExpr(GenericExprState *exprstate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalCaseTestExpr(ExprState *exprstate, @@ -166,9 +169,6 @@ static Datum ExecEvalFieldStore(FieldStoreState *fstate, static Datum ExecEvalRelabelType(GenericExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalCollateClause(GenericExprState *exprstate, - ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); @@ -2754,6 +2754,20 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, } /* ---------------------------------------------------------------- + * ExecEvalCollateExpr + * + * Evaluate a CollateExpr node. + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalCollateExpr(GenericExprState *exprstate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) +{ + return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone); +} + +/* ---------------------------------------------------------------- * ExecEvalCase * * Evaluate a CASE clause. Will have boolean expressions @@ -4029,20 +4043,6 @@ ExecEvalRelabelType(GenericExprState *exprstate, } /* ---------------------------------------------------------------- - * ExecEvalCollateClause - * - * Evaluate a CollateClause node. - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalCollateClause(GenericExprState *exprstate, - ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) -{ - return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone); -} - -/* ---------------------------------------------------------------- * ExecEvalCoerceViaIO * * Evaluate a CoerceViaIO node. @@ -4501,16 +4501,6 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) gstate; } break; - case T_CollateClause: - { - CollateClause *collate = (CollateClause *) node; - GenericExprState *gstate = makeNode(GenericExprState); - - gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCollateClause; - gstate->arg = ExecInitExpr(collate->arg, parent); - state = (ExprState *) gstate; - } - break; case T_CoerceViaIO: { CoerceViaIO *iocoerce = (CoerceViaIO *) node; @@ -4561,6 +4551,16 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) cstate; } break; + case T_CollateExpr: + { + CollateExpr *collate = (CollateExpr *) node; + GenericExprState *gstate = makeNode(GenericExprState); + + gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCollateExpr; + gstate->arg = ExecInitExpr(collate->arg, parent); + state = (ExprState *) gstate; + } + break; case T_CaseExpr: { CaseExpr *caseexpr = (CaseExpr *) node; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index b948af604d8..c0490e93ea5 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -1435,6 +1435,21 @@ _copyConvertRowtypeExpr(ConvertRowtypeExpr *from) } /* + * _copyCollateExpr + */ +static CollateExpr * +_copyCollateExpr(CollateExpr *from) +{ + CollateExpr *newnode = makeNode(CollateExpr); + + COPY_NODE_FIELD(arg); + COPY_SCALAR_FIELD(collOid); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +/* * _copyCaseExpr */ static CaseExpr * @@ -2260,8 +2275,7 @@ _copyCollateClause(CollateClause *from) CollateClause *newnode = makeNode(CollateClause); COPY_NODE_FIELD(arg); - COPY_NODE_FIELD(collnames); - COPY_SCALAR_FIELD(collOid); + COPY_NODE_FIELD(collname); COPY_LOCATION_FIELD(location); return newnode; @@ -4017,6 +4031,9 @@ copyObject(void *from) case T_ConvertRowtypeExpr: retval = _copyConvertRowtypeExpr(from); break; + case T_CollateExpr: + retval = _copyCollateExpr(from); + break; case T_CaseExpr: retval = _copyCaseExpr(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index c8ee4744364..3726006f1d2 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -494,6 +494,16 @@ _equalConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b) } static bool +_equalCollateExpr(CollateExpr *a, CollateExpr *b) +{ + COMPARE_NODE_FIELD(arg); + COMPARE_SCALAR_FIELD(collOid); + COMPARE_LOCATION_FIELD(location); + + return true; +} + +static bool _equalCaseExpr(CaseExpr *a, CaseExpr *b) { COMPARE_SCALAR_FIELD(casetype); @@ -2149,8 +2159,7 @@ static bool _equalCollateClause(CollateClause *a, CollateClause *b) { COMPARE_NODE_FIELD(arg); - COMPARE_NODE_FIELD(collnames); - COMPARE_SCALAR_FIELD(collOid); + COMPARE_NODE_FIELD(collname); COMPARE_LOCATION_FIELD(location); return true; @@ -2583,6 +2592,9 @@ equal(void *a, void *b) case T_ConvertRowtypeExpr: retval = _equalConvertRowtypeExpr(a, b); break; + case T_CollateExpr: + retval = _equalCollateExpr(a, b); + break; case T_CaseExpr: retval = _equalCaseExpr(a, b); break; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index c3c5d8e6e5c..5394851a1f5 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -162,9 +162,6 @@ exprType(Node *expr) case T_RelabelType: type = ((RelabelType *) expr)->resulttype; break; - case T_CollateClause: - type = exprType((Node *) ((CollateClause *) expr)->arg); - break; case T_CoerceViaIO: type = ((CoerceViaIO *) expr)->resulttype; break; @@ -174,6 +171,9 @@ exprType(Node *expr) case T_ConvertRowtypeExpr: type = ((ConvertRowtypeExpr *) expr)->resulttype; break; + case T_CollateExpr: + type = exprType((Node *) ((CollateExpr *) expr)->arg); + break; case T_CaseExpr: type = ((CaseExpr *) expr)->casetype; break; @@ -321,6 +321,8 @@ exprTypmod(Node *expr) return ((RelabelType *) expr)->resulttypmod; case T_ArrayCoerceExpr: return ((ArrayCoerceExpr *) expr)->resulttypmod; + case T_CollateExpr: + return exprTypmod((Node *) ((CollateExpr *) expr)->arg); case T_CaseExpr: { /* @@ -571,9 +573,6 @@ exprCollation(Node *expr) case T_RelabelType: coll = exprCollation((Node *) ((RelabelType *) expr)->arg); break; - case T_CollateClause: - coll = ((CollateClause *) expr)->collOid; - break; case T_CoerceViaIO: { CoerceViaIO *cvio = (CoerceViaIO *) expr; @@ -592,6 +591,9 @@ exprCollation(Node *expr) coll = coercion_expression_result_collation(cre->resulttype, (Node *) cre->arg); break; } + case T_CollateExpr: + coll = ((CollateExpr *) expr)->collOid; + break; case T_CaseExpr: coll = ((CaseExpr *) expr)->casecollation; break; @@ -989,6 +991,10 @@ exprLocation(Node *expr) exprLocation((Node *) cexpr->arg)); } break; + case T_CollateExpr: + /* just use argument's location */ + loc = exprLocation((Node *) ((CollateExpr *) expr)->arg); + break; case T_CaseExpr: /* CASE keyword should always be the first thing */ loc = ((CaseExpr *) expr)->location; @@ -1122,7 +1128,8 @@ exprLocation(Node *expr) } break; case T_CollateClause: - loc = ((CollateClause *) expr)->location; + /* just use argument's location */ + loc = exprLocation(((CollateClause *) expr)->arg); break; case T_SortBy: /* just use argument's location (ignore operator, if any) */ @@ -1436,14 +1443,14 @@ expression_tree_walker(Node *node, break; case T_RelabelType: return walker(((RelabelType *) node)->arg, context); - case T_CollateClause: - return walker(((CollateClause *) node)->arg, context); case T_CoerceViaIO: return walker(((CoerceViaIO *) node)->arg, context); case T_ArrayCoerceExpr: return walker(((ArrayCoerceExpr *) node)->arg, context); case T_ConvertRowtypeExpr: return walker(((ConvertRowtypeExpr *) node)->arg, context); + case T_CollateExpr: + return walker(((CollateExpr *) node)->arg, context); case T_CaseExpr: { CaseExpr *caseexpr = (CaseExpr *) node; @@ -1993,16 +2000,6 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; - case T_CollateClause: - { - CollateClause *collate = (CollateClause *) node; - CollateClause *newnode; - - FLATCOPY(newnode, collate, CollateClause); - MUTATE(newnode->arg, collate->arg, Expr *); - return (Node *) newnode; - } - break; case T_CoerceViaIO: { CoerceViaIO *iocoerce = (CoerceViaIO *) node; @@ -2033,6 +2030,16 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; + case T_CollateExpr: + { + CollateExpr *collate = (CollateExpr *) node; + CollateExpr *newnode; + + FLATCOPY(newnode, collate, CollateExpr); + MUTATE(newnode->arg, collate->arg, Expr *); + return (Node *) newnode; + } + break; case T_CaseExpr: { CaseExpr *caseexpr = (CaseExpr *) node; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 06fd7ff818e..d56e4dac011 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1196,6 +1196,16 @@ _outConvertRowtypeExpr(StringInfo str, ConvertRowtypeExpr *node) } static void +_outCollateExpr(StringInfo str, CollateExpr *node) +{ + WRITE_NODE_TYPE("COLLATE"); + + WRITE_NODE_FIELD(arg); + WRITE_OID_FIELD(collOid); + WRITE_LOCATION_FIELD(location); +} + +static void _outCaseExpr(StringInfo str, CaseExpr *node) { WRITE_NODE_TYPE("CASE"); @@ -2104,11 +2114,10 @@ _outTypeCast(StringInfo str, TypeCast *node) static void _outCollateClause(StringInfo str, CollateClause *node) { - WRITE_NODE_TYPE("COLLATE"); + WRITE_NODE_TYPE("COLLATECLAUSE"); WRITE_NODE_FIELD(arg); - WRITE_NODE_FIELD(collnames); - WRITE_OID_FIELD(collOid); + WRITE_NODE_FIELD(collname); WRITE_LOCATION_FIELD(location); } @@ -2829,9 +2838,6 @@ _outNode(StringInfo str, void *obj) case T_RelabelType: _outRelabelType(str, obj); break; - case T_CollateClause: - _outCollateClause(str, obj); - break; case T_CoerceViaIO: _outCoerceViaIO(str, obj); break; @@ -2841,6 +2847,9 @@ _outNode(StringInfo str, void *obj) case T_ConvertRowtypeExpr: _outConvertRowtypeExpr(str, obj); break; + case T_CollateExpr: + _outCollateExpr(str, obj); + break; case T_CaseExpr: _outCaseExpr(str, obj); break; @@ -3020,6 +3029,9 @@ _outNode(StringInfo str, void *obj) case T_TypeCast: _outTypeCast(str, obj); break; + case T_CollateClause: + _outCollateClause(str, obj); + break; case T_IndexElem: _outIndexElem(str, obj); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 09c5e25012c..6da61285b00 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -744,22 +744,6 @@ _readRelabelType(void) } /* - * _readCollateClause - */ -static CollateClause * -_readCollateClause(void) -{ - READ_LOCALS(CollateClause); - - READ_NODE_FIELD(arg); - READ_NODE_FIELD(collnames); - READ_OID_FIELD(collOid); - READ_LOCATION_FIELD(location); - - READ_DONE(); -} - -/* * _readCoerceViaIO */ static CoerceViaIO * @@ -811,6 +795,21 @@ _readConvertRowtypeExpr(void) } /* + * _readCollateExpr + */ +static CollateExpr * +_readCollateExpr(void) +{ + READ_LOCALS(CollateExpr); + + READ_NODE_FIELD(arg); + READ_OID_FIELD(collOid); + READ_LOCATION_FIELD(location); + + READ_DONE(); +} + +/* * _readCaseExpr */ static CaseExpr * @@ -1286,14 +1285,14 @@ parseNodeString(void) return_value = _readFieldStore(); else if (MATCH("RELABELTYPE", 11)) return_value = _readRelabelType(); - else if (MATCH("COLLATE", 7)) - return_value = _readCollateClause(); else if (MATCH("COERCEVIAIO", 11)) return_value = _readCoerceViaIO(); else if (MATCH("ARRAYCOERCEEXPR", 15)) return_value = _readArrayCoerceExpr(); else if (MATCH("CONVERTROWTYPEEXPR", 18)) return_value = _readConvertRowtypeExpr(); + else if (MATCH("COLLATE", 7)) + return_value = _readCollateExpr(); else if (MATCH("CASE", 4)) return_value = _readCaseExpr(); else if (MATCH("WHEN", 4)) diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index fa0952618b1..8503792df44 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1308,6 +1308,12 @@ find_nonnullable_rels_walker(Node *node, bool top_level) result = find_nonnullable_rels_walker((Node *) expr->arg, top_level); } + else if (IsA(node, CollateExpr)) + { + CollateExpr *expr = (CollateExpr *) node; + + result = find_nonnullable_rels_walker((Node *) expr->arg, top_level); + } else if (IsA(node, NullTest)) { /* IS NOT NULL can be considered strict, but only at top level */ @@ -1510,6 +1516,12 @@ find_nonnullable_vars_walker(Node *node, bool top_level) result = find_nonnullable_vars_walker((Node *) expr->arg, top_level); } + else if (IsA(node, CollateExpr)) + { + CollateExpr *expr = (CollateExpr *) node; + + result = find_nonnullable_vars_walker((Node *) expr->arg, top_level); + } else if (IsA(node, NullTest)) { /* IS NOT NULL can be considered strict, but only at top level */ @@ -2580,6 +2592,42 @@ eval_const_expressions_mutator(Node *node, /* Else we must return the partially-simplified node */ return (Node *) newexpr; } + if (IsA(node, CollateExpr)) + { + /* + * If we can simplify the input to a constant, then we don't need the + * CollateExpr node anymore: just change the constcollid field of the + * Const node. Otherwise, must copy the CollateExpr node. + */ + CollateExpr *collate = (CollateExpr *) node; + Node *arg; + + arg = eval_const_expressions_mutator((Node *) collate->arg, + context); + + /* + * If we find stacked CollateExprs, we can discard all but the top one. + */ + while (arg && IsA(arg, CollateExpr)) + arg = (Node *) ((CollateExpr *) arg)->arg; + + if (arg && IsA(arg, Const)) + { + Const *con = (Const *) arg; + + con->constcollid = collate->collOid; + return (Node *) con; + } + else + { + CollateExpr *newcollate = makeNode(CollateExpr); + + newcollate->arg = (Expr *) arg; + newcollate->collOid = collate->collOid; + newcollate->location = collate->location; + return (Node *) newcollate; + } + } if (IsA(node, CaseExpr)) { /*---------- diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 373d2adc71c..1633499f939 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1993,8 +1993,7 @@ opt_collate_clause: { CollateClause *n = makeNode(CollateClause); n->arg = NULL; - n->collnames = $2; - n->collOid = InvalidOid; + n->collname = $2; n->location = @1; $$ = (Node *) n; } @@ -2537,8 +2536,7 @@ ColConstraint: */ CollateClause *n = makeNode(CollateClause); n->arg = NULL; - n->collnames = $2; - n->collOid = InvalidOid; + n->collname = $2; n->location = @1; $$ = (Node *) n; } @@ -9690,8 +9688,8 @@ a_expr: c_expr { $$ = $1; } | a_expr COLLATE any_name { CollateClause *n = makeNode(CollateClause); - n->arg = (Expr *) $1; - n->collnames = $3; + n->arg = $1; + n->collname = $3; n->location = @2; $$ = (Node *) n; } diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 2fd808d26b2..6aff34dd90d 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -279,11 +279,17 @@ coerce_type(ParseState *pstate, Node *node, if (result) return result; } - if (IsA(node, CollateClause)) + if (IsA(node, CollateExpr)) { - CollateClause *cc = (CollateClause *) node; + /* + * XXX very ugly kluge to push the coercion underneath the CollateExpr. + * This needs to be rethought, as it almost certainly doesn't cover + * all cases. + */ + CollateExpr *cc = (CollateExpr *) node; - cc->arg = (Expr *) coerce_type(pstate, (Node *) cc->arg, inputTypeId, targetTypeId, targetTypeMod, + cc->arg = (Expr *) coerce_type(pstate, (Node *) cc->arg, + inputTypeId, targetTypeId, targetTypeMod, ccontext, cformat, location); return (Node *) cc; } @@ -2121,7 +2127,7 @@ select_common_collation(ParseState *pstate, List *exprs, bool none_ok) { Node *pexpr = (Node *) lfirst(lc); Oid pcoll = exprCollation(pexpr); - bool pexplicit = IsA(pexpr, CollateClause); + bool pexplicit = IsA(pexpr, CollateExpr); if (pcoll && pexplicit) { @@ -2130,7 +2136,7 @@ select_common_collation(ParseState *pstate, List *exprs, bool none_ok) { Node *nexpr = (Node *) lfirst(lc2); Oid ncoll = exprCollation(nexpr); - bool nexplicit = IsA(nexpr, CollateClause); + bool nexplicit = IsA(nexpr, CollateExpr); if (!ncoll || !nexplicit) continue; diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 7a4f8cc2497..17bd2bf50ae 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -318,6 +318,7 @@ transformExpr(ParseState *pstate, Node *expr) case T_CoerceViaIO: case T_ArrayCoerceExpr: case T_ConvertRowtypeExpr: + case T_CollateExpr: case T_CaseTestExpr: case T_ArrayExpr: case T_CoerceToDomain: @@ -2103,11 +2104,11 @@ transformTypeCast(ParseState *pstate, TypeCast *tc) static Node * transformCollateClause(ParseState *pstate, CollateClause *c) { - CollateClause *newc; + CollateExpr *newc; Oid argtype; - newc = makeNode(CollateClause); - newc->arg = (Expr *) transformExpr(pstate, (Node *) c->arg); + newc = makeNode(CollateExpr); + newc->arg = (Expr *) transformExpr(pstate, c->arg); argtype = exprType((Node *) newc->arg); /* @@ -2121,8 +2122,7 @@ transformCollateClause(ParseState *pstate, CollateClause *c) format_type_be(argtype)), parser_errposition(pstate, c->location))); - newc->collOid = LookupCollation(pstate, c->collnames, c->location); - newc->collnames = c->collnames; + newc->collOid = LookupCollation(pstate, c->collname, c->location); newc->location = c->location; return (Node *) newc; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index c0eaea71a66..fd1529fb3f9 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -1583,7 +1583,7 @@ FigureColnameInternal(Node *node, char **name) } break; case T_CollateClause: - return FigureColnameInternal((Node *) ((CollateClause *) node)->arg, name); + return FigureColnameInternal(((CollateClause *) node)->arg, name); case T_CaseExpr: strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult, name); diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 2ba9bf51816..f413593f602 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -471,7 +471,7 @@ GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid) { /* We have a raw COLLATE clause, so look up the collation */ location = coldef->collClause->location; - result = LookupCollation(pstate, coldef->collClause->collnames, + result = LookupCollation(pstate, coldef->collClause->collname, location); } else if (OidIsValid(coldef->collOid)) diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index e876853af02..06baf89886a 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -2467,7 +2467,7 @@ transformColumnType(CreateStmtContext *cxt, ColumnDef *column) Oid collOid; collOid = LookupCollation(cxt->pstate, - column->collClause->collnames, + column->collClause->collname, column->collClause->location); /* Complain if COLLATE is applied to an uncollatable type */ if (!OidIsValid(typtup->typcollation)) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 7cbd0222cb2..ac0c53a7f32 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -226,6 +226,7 @@ static void get_coercion_expr(Node *arg, deparse_context *context, Node *parentNode); static void get_const_expr(Const *constval, deparse_context *context, int showtype); +static void get_const_collation(Const *constval, deparse_context *context); static void simple_quote_literal(StringInfo buf, const char *val); static void get_sublink_expr(SubLink *sublink, deparse_context *context); static void get_from_clause(Query *query, const char *prefix, @@ -5075,21 +5076,6 @@ get_rule_expr(Node *node, deparse_context *context, } break; - case T_CollateClause: - { - CollateClause *collate = (CollateClause *) node; - Node *arg = (Node *) collate->arg; - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, showimplicit, node); - appendStringInfo(buf, " COLLATE %s", - generate_collation_name(collate->collOid)); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - break; - case T_CoerceViaIO: { CoerceViaIO *iocoerce = (CoerceViaIO *) node; @@ -5152,6 +5138,21 @@ get_rule_expr(Node *node, deparse_context *context, } break; + case T_CollateExpr: + { + CollateExpr *collate = (CollateExpr *) node; + Node *arg = (Node *) collate->arg; + + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, '('); + get_rule_expr_paren(arg, context, showimplicit, node); + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(collate->collOid)); + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); + } + break; + case T_CaseExpr: { CaseExpr *caseexpr = (CaseExpr *) node; @@ -5974,6 +5975,10 @@ get_coercion_expr(Node *arg, deparse_context *context, * showtype can be -1 to never show "::typename" decoration, or +1 to always * show it, or 0 to show it only if the constant wouldn't be assumed to be * the right type by default. + * + * If the Const's collation isn't default for its type, show that too. + * This can only happen in trees that have been through constant-folding. + * We assume we don't need to do this when showtype is -1. * ---------- */ static void @@ -5994,9 +5999,12 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) */ appendStringInfo(buf, "NULL"); if (showtype >= 0) + { appendStringInfo(buf, "::%s", format_type_with_typemod(constval->consttype, constval->consttypmod)); + get_const_collation(constval, context); + } return; } @@ -6097,6 +6105,28 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) appendStringInfo(buf, "::%s", format_type_with_typemod(constval->consttype, constval->consttypmod)); + + get_const_collation(constval, context); +} + +/* + * helper for get_const_expr: append COLLATE if needed + */ +static void +get_const_collation(Const *constval, deparse_context *context) +{ + StringInfo buf = context->buf; + + if (OidIsValid(constval->constcollid)) + { + Oid typcollation = get_typcollation(constval->consttype); + + if (constval->constcollid != typcollation) + { + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(constval->constcollid)); + } + } } /* diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 27ce7955772..657015616cd 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201103111 +#define CATALOG_VERSION_NO 201103112 #endif diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index cbaf123ee9d..8ed819b4dd4 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -148,6 +148,7 @@ typedef enum NodeTag T_CoerceViaIO, T_ArrayCoerceExpr, T_ConvertRowtypeExpr, + T_CollateExpr, T_CaseExpr, T_CaseWhen, T_CaseTestExpr, @@ -169,7 +170,6 @@ typedef enum NodeTag T_JoinExpr, T_FromExpr, T_IntoClause, - T_CollateClause, /* * TAGS FOR EXPRESSION STATE NODES (execnodes.h) @@ -377,6 +377,7 @@ typedef enum NodeTag T_A_ArrayExpr, T_ResTarget, T_TypeCast, + T_CollateClause, T_SortBy, T_WindowDef, T_RangeSubselect, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 9d4515cb27f..904bd5e9e18 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -266,6 +266,17 @@ typedef struct TypeCast } TypeCast; /* + * CollateClause - a COLLATE expression + */ +typedef struct CollateClause +{ + NodeTag type; + Node *arg; /* input expression */ + List *collname; /* possibly-qualified collation name */ + int location; /* token location, or -1 if unknown */ +} CollateClause; + +/* * FuncCall - a function or aggregate invocation * * agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)'. diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 8c366df5f56..41fd56e1bf1 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -653,18 +653,6 @@ typedef struct RelabelType int location; /* token location, or -1 if unknown */ } RelabelType; -/* - * CollateClause - COLLATE - */ -typedef struct CollateClause -{ - Expr xpr; - Expr *arg; /* original expression */ - List *collnames; /* assigned collation */ - Oid collOid; /* resolved collation OID */ - int location; /* token location, or -1 if unknown */ -} CollateClause; - /* ---------------- * CoerceViaIO * @@ -731,6 +719,18 @@ typedef struct ConvertRowtypeExpr } ConvertRowtypeExpr; /*---------- + * CollateExpr - COLLATE + *---------- + */ +typedef struct CollateExpr +{ + Expr xpr; + Expr *arg; /* input expression */ + Oid collOid; /* collation's OID */ + int location; /* token location, or -1 if unknown */ +} CollateExpr; + +/*---------- * CaseExpr - a CASE expression * * We support two distinct forms of CASE expression: diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 7af6eee088e..689686b7825 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -5350,6 +5350,9 @@ exec_simple_check_node(Node *node) case T_ConvertRowtypeExpr: return exec_simple_check_node((Node *) ((ConvertRowtypeExpr *) node)->arg); + case T_CollateExpr: + return exec_simple_check_node((Node *) ((CollateExpr *) node)->arg); + case T_CaseExpr: { CaseExpr *expr = (CaseExpr *) node; diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out index 2102298abaa..53595b6e10c 100644 --- a/src/test/regress/expected/collate.linux.utf8.out +++ b/src/test/regress/expected/collate.linux.utf8.out @@ -107,11 +107,11 @@ SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "C"; SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "en_US.utf8"; ERROR: collation mismatch between explicit collations "C" and "en_US.utf8" -LINE 1: ...* FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "e... +LINE 1: ...ELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLL... ^ SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "en_US"; ERROR: collation mismatch between explicit collations "C" and "en_US" -LINE 1: ...* FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "e... +LINE 1: ...ELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLL... ^ CREATE DOMAIN testdomain_sv AS text COLLATE "sv_SE.utf8"; CREATE DOMAIN testdomain_i AS int COLLATE "sv_SE.utf8"; -- fails |