Split CollateClause into separate raw and analyzed node types.
authorTom Lane <[email protected]>
Fri, 11 Mar 2011 21:27:51 +0000 (16:27 -0500)
committerTom Lane <[email protected]>
Fri, 11 Mar 2011 21:28:18 +0000 (16:28 -0500)
CollateClause is now used only in raw grammar output, and CollateExpr after
parse analysis.  This is for clarity and to avoid carrying collation names
in post-analysis parse trees: that's both wasteful and possibly misleading,
since the collation's name could be changed while the parsetree still
exists.

Also, clean up assorted infelicities and omissions in processing of the
node type.

22 files changed:
src/backend/catalog/dependency.c
src/backend/commands/typecmds.c
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_target.c
src/backend/parser/parse_type.c
src/backend/parser/parse_utilcmd.c
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h
src/pl/plpgsql/src/pl_exec.c
src/test/regress/expected/collate.linux.utf8.out

index bce0e076837f57857c8c19d82b08f5cb51b1f766..9e2028a64ff6d2d5c67e5f493ba8271966d70d48 100644 (file)
@@ -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);
                    }
index 3513256b9a54874b9c42f1489aff67c1bbcb01ae..ee3bca17d17a3419b2eb8fdf22fed98e22cfce02 100644 (file)
@@ -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;
 
index 2b5dd2dbf85e46efd7f48db684256656d91983f4..0faf52dfd793b1167624f3951bdc6d33330720ed 100644 (file)
@@ -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);
@@ -2753,6 +2753,20 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
    return HeapTupleGetDatum(result);
 }
 
+/* ----------------------------------------------------------------
+ *     ExecEvalCollateExpr
+ *
+ *     Evaluate a CollateExpr node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalCollateExpr(GenericExprState *exprstate,
+                   ExprContext *econtext,
+                   bool *isNull, ExprDoneCond *isDone)
+{
+   return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
+}
+
 /* ----------------------------------------------------------------
  *     ExecEvalCase
  *
@@ -4028,20 +4042,6 @@ ExecEvalRelabelType(GenericExprState *exprstate,
    return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
 }
 
-/* ----------------------------------------------------------------
- *     ExecEvalCollateClause
- *
- *     Evaluate a CollateClause node.
- * ----------------------------------------------------------------
- */
-static Datum
-ExecEvalCollateClause(GenericExprState *exprstate,
-                   ExprContext *econtext,
-                   bool *isNull, ExprDoneCond *isDone)
-{
-   return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
-}
-
 /* ----------------------------------------------------------------
  *     ExecEvalCoerceViaIO
  *
@@ -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;
index b948af604d8149b9d95f9c923cbb983b2df3eb40..c0490e93ea50c045aff08da3ed6a16bcca5b545b 100644 (file)
@@ -1434,6 +1434,21 @@ _copyConvertRowtypeExpr(ConvertRowtypeExpr *from)
    return newnode;
 }
 
+/*
+ * _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
  */
@@ -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;
index c8ee4744364e7b925415c66c23d0bc2d78b68ffa..3726006f1d2fd5e0eaf77521777a749dd39bf363 100644 (file)
@@ -493,6 +493,16 @@ _equalConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b)
    return true;
 }
 
+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)
 {
@@ -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;
index c3c5d8e6e5c3e910e6caf953d228e5bf13d60a1b..5394851a1f55bfcb744b0680da4883f16a8bdef1 100644 (file)
@@ -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;
index 06fd7ff818e4ed45c7cbb42ab2ef1f38848839bb..d56e4dac011cd613eaa152df59282cf72ac1890d 100644 (file)
@@ -1195,6 +1195,16 @@ _outConvertRowtypeExpr(StringInfo str, ConvertRowtypeExpr *node)
    WRITE_LOCATION_FIELD(location);
 }
 
+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)
 {
@@ -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;
index 09c5e25012c21e73fa103afcd2d17f0482e35dbe..6da61285b004570cd91ebf36c1799ded9bfcacff 100644 (file)
@@ -743,22 +743,6 @@ _readRelabelType(void)
    READ_DONE();
 }
 
-/*
- * _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
  */
@@ -810,6 +794,21 @@ _readConvertRowtypeExpr(void)
    READ_DONE();
 }
 
+/*
+ * _readCollateExpr
+ */
+static CollateExpr *
+_readCollateExpr(void)
+{
+   READ_LOCALS(CollateExpr);
+
+   READ_NODE_FIELD(arg);
+   READ_OID_FIELD(collOid);
+   READ_LOCATION_FIELD(location);
+
+   READ_DONE();
+}
+
 /*
  * _readCaseExpr
  */
@@ -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))
index fa0952618b13367029be0ea21712c972d58237b8..8503792df448ccde6b03d728e61d28f6fb81c6a6 100644 (file)
@@ -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))
    {
        /*----------
index 373d2adc71c90a58318e9c46e0c55024ab7caede..1633499f93974b2e0c1cf634f8ef2738cd292c02 100644 (file)
@@ -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;
                }
index 2fd808d26b200acaace440b464b5cfee4c975c1b..6aff34dd90d5b2e6124787e242bcc76a476aa318 100644 (file)
@@ -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;
index 7a4f8cc2497aaf9f669dc3b1d65016a383f425da..17bd2bf50aee9d5322659b94621d4762b6348120 100644 (file)
@@ -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;
index c0eaea71a6649cea58ef1a922e8ea7dd94df0e88..fd1529fb3f9e5da9ab2e8975ea8b54cec48c888d 100644 (file)
@@ -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);
index 2ba9bf5181642d3f4896c25e14f58ab72800dc08..f413593f60220a6cc0e0080ded0836c6f310f513 100644 (file)
@@ -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))
index e876853af02c9a37b74e4031ea46a753898b4876..06baf89886a9dd08813f7a0e12571a48d1661809 100644 (file)
@@ -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))
index 7cbd0222cb2e77b59ec3264c8ffabb68addeb1a5..ac0c53a7f320ed3522e8eb3dca75f6cf3e07dfd3 100644 (file)
@@ -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));
+       }
+   }
 }
 
 /*
index 27ce7955772e92038dd8b4bf0cac80864e297e7f..657015616cdd3bd1d86d49dd76d434b8e625fc13 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201103111
+#define CATALOG_VERSION_NO 201103112
 
 #endif
index cbaf123ee9d11a9914bd0df39cfeb86880e73778..8ed819b4dd40412e0447640457921f6813b021fc 100644 (file)
@@ -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,
index 9d4515cb27f39f5cae6165eb7385982a67aeb397..904bd5e9e18757a843bec97e275511fe1dbd88ec 100644 (file)
@@ -265,6 +265,17 @@ typedef struct TypeCast
    int         location;       /* token location, or -1 if unknown */
 } 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
  *
index 8c366df5f5619d27e80fb99011fc448425d202aa..41fd56e1bf13e78d9af3ca62712490a1f25160d2 100644 (file)
@@ -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
  *
@@ -730,6 +718,18 @@ typedef struct ConvertRowtypeExpr
    int         location;       /* token location, or -1 if unknown */
 } 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
  *
index 7af6eee088e3d7868f7a0e05a3a747eabf539f72..689686b7825656fa3078eb1676d24216d7b94e40 100644 (file)
@@ -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;
index 2102298abaa10e929c5b5da76d1cefcc9bdd5bc7..53595b6e10cfcad895f7bb1ec323f9e8f112b759 100644 (file)
@@ -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