mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +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:
@ -16,6 +16,7 @@
|
||||
|
||||
#include "catalog/pg_cast.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_inherits_fn.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
@ -216,6 +217,7 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
|
||||
newcon->consttype = baseTypeId;
|
||||
newcon->consttypmod = inputTypeMod;
|
||||
newcon->constcollid = get_typcollation(newcon->consttype);
|
||||
newcon->constlen = typeLen(targetType);
|
||||
newcon->constbyval = typeByVal(targetType);
|
||||
newcon->constisnull = con->constisnull;
|
||||
@ -277,6 +279,14 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
if (IsA(node, CollateClause))
|
||||
{
|
||||
CollateClause *cc = (CollateClause *) node;
|
||||
|
||||
cc->arg = (Expr *) coerce_type(pstate, (Node *) cc->arg, inputTypeId, targetTypeId, targetTypeMod,
|
||||
ccontext, cformat, location);
|
||||
return (Node *) cc;
|
||||
}
|
||||
pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
|
||||
&funcId);
|
||||
if (pathtype != COERCION_PATH_NONE)
|
||||
@ -718,6 +728,7 @@ build_coercion_expression(Node *node,
|
||||
FuncExpr *fexpr;
|
||||
List *args;
|
||||
Const *cons;
|
||||
Oid collation;
|
||||
|
||||
Assert(OidIsValid(funcId));
|
||||
|
||||
@ -749,7 +760,9 @@ build_coercion_expression(Node *node,
|
||||
args = lappend(args, cons);
|
||||
}
|
||||
|
||||
fexpr = makeFuncExpr(funcId, targetTypeId, args, cformat);
|
||||
collation = coercion_expression_result_collation(targetTypeId, node);
|
||||
|
||||
fexpr = makeFuncExpr(funcId, targetTypeId, args, collation, cformat);
|
||||
fexpr->location = location;
|
||||
return (Node *) fexpr;
|
||||
}
|
||||
@ -2081,3 +2094,120 @@ typeIsOfTypedTable(Oid reltypeId, Oid reloftypeId)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* select_common_collation() -- determine one collation to apply for
|
||||
* an expression node, for evaluating the expression itself or to
|
||||
* label the result of the expression node.
|
||||
*
|
||||
* none_ok means that it is permitted to return "no" collation. It is
|
||||
* then not possible to sort the result value of whatever expression
|
||||
* is applying this. none_ok = true reflects the rules of SQL
|
||||
* standard clause "Result of data type combinations", none_ok = false
|
||||
* reflects the rules of clause "Collation determination" (in some
|
||||
* cases invoked via "Grouping operations").
|
||||
*/
|
||||
Oid
|
||||
select_common_collation(ParseState *pstate, List *exprs, bool none_ok)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
/*
|
||||
* Check if there are any explicit collation derivations. If so,
|
||||
* they must all be the same.
|
||||
*/
|
||||
foreach(lc, exprs)
|
||||
{
|
||||
Node *pexpr = (Node *) lfirst(lc);
|
||||
Oid pcoll = exprCollation(pexpr);
|
||||
bool pexplicit = IsA(pexpr, CollateClause);
|
||||
|
||||
if (pcoll && pexplicit)
|
||||
{
|
||||
ListCell *lc2;
|
||||
for_each_cell(lc2, lnext(lc))
|
||||
{
|
||||
Node *nexpr = (Node *) lfirst(lc2);
|
||||
Oid ncoll = exprCollation(nexpr);
|
||||
bool nexplicit = IsA(nexpr, CollateClause);
|
||||
|
||||
if (!ncoll || !nexplicit)
|
||||
continue;
|
||||
|
||||
if (ncoll != pcoll)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_COLLATION_MISMATCH),
|
||||
errmsg("collation mismatch between explicit collations \"%s\" and \"%s\"",
|
||||
get_collation_name(pcoll),
|
||||
get_collation_name(ncoll)),
|
||||
parser_errposition(pstate, exprLocation(nexpr))));
|
||||
}
|
||||
|
||||
return pcoll;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there are any implicit collation derivations.
|
||||
*/
|
||||
foreach(lc, exprs)
|
||||
{
|
||||
Node *pexpr = (Node *) lfirst(lc);
|
||||
Oid pcoll = exprCollation(pexpr);
|
||||
|
||||
if (pcoll && pcoll != DEFAULT_COLLATION_OID)
|
||||
{
|
||||
ListCell *lc2;
|
||||
for_each_cell(lc2, lnext(lc))
|
||||
{
|
||||
Node *nexpr = (Node *) lfirst(lc2);
|
||||
Oid ncoll = exprCollation(nexpr);
|
||||
|
||||
if (!ncoll || ncoll == DEFAULT_COLLATION_OID)
|
||||
continue;
|
||||
|
||||
if (ncoll != pcoll)
|
||||
{
|
||||
if (none_ok)
|
||||
return InvalidOid;
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_COLLATION_MISMATCH),
|
||||
errmsg("collation mismatch between implicit collations \"%s\" and \"%s\"",
|
||||
get_collation_name(pcoll),
|
||||
get_collation_name(ncoll)),
|
||||
errhint("You can override the collation by applying the COLLATE clause to one or both expressions."),
|
||||
parser_errposition(pstate, exprLocation(nexpr))));
|
||||
}
|
||||
}
|
||||
|
||||
return pcoll;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(lc, exprs)
|
||||
{
|
||||
Node *pexpr = (Node *) lfirst(lc);
|
||||
Oid pcoll = exprCollation(pexpr);
|
||||
|
||||
if (pcoll == DEFAULT_COLLATION_OID)
|
||||
{
|
||||
ListCell *lc2;
|
||||
for_each_cell(lc2, lnext(lc))
|
||||
{
|
||||
Node *nexpr = (Node *) lfirst(lc2);
|
||||
Oid ncoll = exprCollation(nexpr);
|
||||
|
||||
if (ncoll != pcoll)
|
||||
break;
|
||||
}
|
||||
|
||||
return pcoll;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Else use default
|
||||
*/
|
||||
return InvalidOid;
|
||||
}
|
||||
|
Reference in New Issue
Block a user