1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-26 12:21:12 +03:00

Per-column collation support

This adds collation support for columns and domains, a COLLATE clause
to override it per expression, and B-tree index support.

Peter Eisentraut
reviewed by Pavel Stehule, Itagaki Takahiro, Robert Haas, Noah Misch
This commit is contained in:
Peter Eisentraut
2011-02-08 23:04:18 +02:00
parent 1703f0e8da
commit 414c5a2ea6
156 changed files with 4519 additions and 582 deletions

View File

@ -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;
@ -459,6 +463,215 @@ exprTypmod(Node *expr)
return -1;
}
/*
* 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
@ -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: