aboutsummaryrefslogtreecommitdiff
path: root/src/backend/nodes/nodeFuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/nodes/nodeFuncs.c')
-rw-r--r--src/backend/nodes/nodeFuncs.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index d17b347e45c..8a23047d382 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -14,6 +14,7 @@
*/
#include "postgres.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
@@ -161,6 +162,9 @@ 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;
@@ -460,6 +464,215 @@ exprTypmod(Node *expr)
}
/*
+ * exprCollation -
+ * returns the Oid of the collation of the expression's result.
+ */
+Oid
+exprCollation(Node *expr)
+{
+ Oid coll;
+
+ if (!expr)
+ return InvalidOid;
+
+ switch (nodeTag(expr))
+ {
+ case T_Var:
+ coll = ((Var *) expr)->varcollid;
+ break;
+ case T_Const:
+ coll = ((Const *) expr)->constcollid;
+ break;
+ case T_Param:
+ coll = ((Param *) expr)->paramcollation;
+ break;
+ case T_Aggref:
+ coll = ((Aggref *) expr)->collid;
+ break;
+ case T_WindowFunc:
+ coll = ((WindowFunc *) expr)->collid;
+ break;
+ case T_ArrayRef:
+ coll = ((ArrayRef *) expr)->refcollid;
+ break;
+ case T_FuncExpr:
+ coll = ((FuncExpr *) expr)->collid;
+ break;
+ case T_NamedArgExpr:
+ coll = exprCollation((Node *) ((NamedArgExpr *) expr)->arg);
+ break;
+ case T_OpExpr:
+ coll = ((OpExpr *) expr)->collid;
+ break;
+ case T_DistinctExpr:
+ coll = ((DistinctExpr *) expr)->collid;
+ break;
+ case T_ScalarArrayOpExpr:
+ coll = ((ScalarArrayOpExpr *) expr)->collid;
+ break;
+ case T_BoolExpr:
+ coll = InvalidOid; /* not applicable */
+ break;
+ case T_SubLink:
+ {
+ SubLink *sublink = (SubLink *) expr;
+
+ if (sublink->subLinkType == EXPR_SUBLINK ||
+ sublink->subLinkType == ARRAY_SUBLINK)
+ {
+ /* get the collation of the subselect's first target column */
+ Query *qtree = (Query *) sublink->subselect;
+ TargetEntry *tent;
+
+ if (!qtree || !IsA(qtree, Query))
+ elog(ERROR, "cannot get collation for untransformed sublink");
+ tent = (TargetEntry *) linitial(qtree->targetList);
+ Assert(IsA(tent, TargetEntry));
+ Assert(!tent->resjunk);
+ coll = exprCollation((Node *) tent->expr);
+ /* note we don't need to care if it's an array */
+ }
+ else
+ coll = InvalidOid;
+ }
+ break;
+ case T_SubPlan:
+ {
+ SubPlan *subplan = (SubPlan *) expr;
+
+ if (subplan->subLinkType == EXPR_SUBLINK ||
+ subplan->subLinkType == ARRAY_SUBLINK)
+ {
+ /* get the collation of the subselect's first target column */
+ /* note we don't need to care if it's an array */
+ coll = subplan->firstColCollation;
+ }
+ else
+ {
+ /* for all other subplan types, result is boolean */
+ coll = InvalidOid;
+ }
+ }
+ break;
+ case T_AlternativeSubPlan:
+ {
+ AlternativeSubPlan *asplan = (AlternativeSubPlan *) expr;
+
+ /* subplans should all return the same thing */
+ coll = exprCollation((Node *) linitial(asplan->subplans));
+ }
+ break;
+ case T_FieldSelect:
+ coll = ((FieldSelect *) expr)->resultcollation;
+ break;
+ case T_FieldStore:
+ coll = InvalidOid; /* not applicable */
+ break;
+ 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;
+ coll = coercion_expression_result_collation(cvio->resulttype, (Node *) cvio->arg);
+ break;
+ }
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *ace = (ArrayCoerceExpr *) expr;
+ coll = coercion_expression_result_collation(ace->resulttype, (Node *) ace->arg);
+ break;
+ }
+ case T_ConvertRowtypeExpr:
+ {
+ ConvertRowtypeExpr *cre = (ConvertRowtypeExpr *) expr;
+ coll = coercion_expression_result_collation(cre->resulttype, (Node *) cre->arg);
+ break;
+ }
+ case T_CaseExpr:
+ coll = ((CaseExpr *) expr)->casecollation;
+ break;
+ case T_CaseTestExpr:
+ coll = ((CaseTestExpr *) expr)->collation;
+ break;
+ case T_ArrayExpr:
+ coll = get_typcollation(((ArrayExpr *) expr)->array_typeid);
+ break;
+ case T_RowExpr:
+ coll = InvalidOid; /* not applicable */
+ break;
+ case T_RowCompareExpr:
+ coll = InvalidOid; /* not applicable */
+ break;
+ case T_CoalesceExpr:
+ coll = ((CoalesceExpr *) expr)->coalescecollation;
+ break;
+ case T_MinMaxExpr:
+ coll = ((MinMaxExpr *) expr)->collid;
+ break;
+ case T_XmlExpr:
+ if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
+ coll = DEFAULT_COLLATION_OID;
+ else
+ coll = InvalidOid;
+ break;
+ case T_NullIfExpr:
+ coll = exprCollation((Node *) linitial(((NullIfExpr *) expr)->args));
+ break;
+ case T_NullTest:
+ coll = InvalidOid; /* not applicable */
+ break;
+ case T_BooleanTest:
+ coll = InvalidOid; /* not applicable */
+ break;
+ case T_CoerceToDomain:
+ coll = get_typcollation(((CoerceToDomain *) expr)->resulttype);
+ if (coll == DEFAULT_COLLATION_OID)
+ coll = exprCollation((Node *) ((CoerceToDomain *) expr)->arg);
+ break;
+ case T_CoerceToDomainValue:
+ coll = get_typcollation(((CoerceToDomainValue *) expr)->typeId);
+ break;
+ case T_SetToDefault:
+ coll = ((SetToDefault *) expr)->collid;
+ break;
+ case T_CurrentOfExpr:
+ coll = InvalidOid; /* not applicable */
+ break;
+ case T_PlaceHolderVar:
+ coll = exprCollation((Node *) ((PlaceHolderVar *) expr)->phexpr);
+ break;
+ default:
+ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
+ coll = InvalidOid; /* keep compiler quiet */
+ break;
+ }
+
+ return coll;
+}
+
+/*
+ * Compute the result collation of a coercion-like expression that
+ * converts arg to resulttype.
+ */
+Oid
+coercion_expression_result_collation(Oid resulttype, Node *arg)
+{
+ if (type_is_collatable(resulttype))
+ {
+ if (type_is_collatable(exprType(arg)))
+ return exprCollation(arg);
+ else
+ return DEFAULT_COLLATION_OID;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
* exprIsLengthCoercion
* Detect whether an expression tree is an application of a datatype's
* typmod-coercion function. Optionally extract the result's typmod.
@@ -908,6 +1121,9 @@ exprLocation(Node *expr)
loc = leftmostLoc(loc, tc->location);
}
break;
+ case T_CollateClause:
+ loc = ((CollateClause *) expr)->location;
+ break;
case T_SortBy:
/* just use argument's location (ignore operator, if any) */
loc = exprLocation(((SortBy *) expr)->node);
@@ -1220,6 +1436,8 @@ 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:
@@ -1776,6 +1994,16 @@ 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;
@@ -2471,6 +2699,8 @@ bool
return true;
}
break;
+ case T_CollateClause:
+ return walker(((CollateClause *) node)->arg, context);
case T_SortBy:
return walker(((SortBy *) node)->node, context);
case T_WindowDef: