1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-03 20:02:46 +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

@ -166,6 +166,9 @@ 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);
@ -1202,7 +1205,7 @@ init_fcache(Oid foid, FuncExprState *fcache,
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
fcache->func.fn_expr = (Node *) fcache->xprstate.expr;
fmgr_info_expr((Node *) fcache->xprstate.expr, &(fcache->func));
/* Initialize the function call parameter struct as well */
InitFunctionCallInfoData(fcache->fcinfo_data, &(fcache->func),
@ -4025,6 +4028,20 @@ 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
*
@ -4114,7 +4131,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
econtext->ecxt_per_query_memory);
/* Initialize additional info */
astate->elemfunc.fn_expr = (Node *) acoerce;
fmgr_info_expr((Node *) acoerce, &(astate->elemfunc));
}
/*
@ -4484,6 +4501,16 @@ 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;
@ -4657,6 +4684,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
List *outlist;
ListCell *l;
ListCell *l2;
ListCell *l3;
int i;
rstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalRowCompare;
@ -4685,10 +4713,11 @@ ExecInitExpr(Expr *node, PlanState *parent)
Assert(list_length(rcexpr->opfamilies) == nopers);
rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
i = 0;
forboth(l, rcexpr->opnos, l2, rcexpr->opfamilies)
forthree(l, rcexpr->opnos, l2, rcexpr->opfamilies, l3, rcexpr->collids)
{
Oid opno = lfirst_oid(l);
Oid opfamily = lfirst_oid(l2);
Oid collid = lfirst_oid(l3);
int strategy;
Oid lefttype;
Oid righttype;
@ -4710,6 +4739,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
* does this code.
*/
fmgr_info(proc, &(rstate->funcs[i]));
fmgr_info_collation(collid, &(rstate->funcs[i]));
i++;
}
state = (ExprState *) rstate;
@ -4769,6 +4799,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
* code.
*/
fmgr_info(typentry->cmp_proc, &(mstate->cfunc));
fmgr_info_collation(minmaxexpr->collid, &(mstate->cfunc));
state = (ExprState *) mstate;
}
break;

View File

@ -937,11 +937,15 @@ ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
if (skipjunk && tle->resjunk)
continue;
TupleDescInitEntry(typeInfo,
cur_resno++,
cur_resno,
tle->resname,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
TupleDescInitEntryCollation(typeInfo,
cur_resno,
exprCollation((Node *) tle->expr));
cur_resno++;
}
return typeInfo;
@ -969,11 +973,15 @@ ExecTypeFromExprList(List *exprList)
sprintf(fldname, "f%d", cur_resno);
TupleDescInitEntry(typeInfo,
cur_resno++,
cur_resno,
fldname,
exprType(e),
exprTypmod(e),
0);
TupleDescInitEntryCollation(typeInfo,
cur_resno,
exprCollation(e));
cur_resno++;
}
return typeInfo;

View File

@ -140,6 +140,7 @@ typedef struct AggStatePerAggData
/* deconstructed sorting information (arrays of length numSortCols) */
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *sortCollations;
bool *sortNullsFirst;
/*
@ -315,12 +316,14 @@ initialize_aggregates(AggState *aggstate,
(peraggstate->numInputs == 1) ?
tuplesort_begin_datum(peraggstate->evaldesc->attrs[0]->atttypid,
peraggstate->sortOperators[0],
peraggstate->sortCollations[0],
peraggstate->sortNullsFirst[0],
work_mem, false) :
tuplesort_begin_heap(peraggstate->evaldesc,
peraggstate->numSortCols,
peraggstate->sortColIdx,
peraggstate->sortOperators,
peraggstate->sortCollations,
peraggstate->sortNullsFirst,
work_mem, false);
}
@ -1668,16 +1671,17 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggref->aggtype,
transfn_oid,
finalfn_oid,
aggref->collid,
&transfnexpr,
&finalfnexpr);
fmgr_info(transfn_oid, &peraggstate->transfn);
peraggstate->transfn.fn_expr = (Node *) transfnexpr;
fmgr_info_expr((Node *) transfnexpr, &peraggstate->transfn);
if (OidIsValid(finalfn_oid))
{
fmgr_info(finalfn_oid, &peraggstate->finalfn);
peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
fmgr_info_expr((Node *) finalfnexpr, &peraggstate->finalfn);
}
get_typlenbyval(aggref->aggtype,
@ -1786,6 +1790,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
(AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
peraggstate->sortOperators =
(Oid *) palloc(numSortCols * sizeof(Oid));
peraggstate->sortCollations =
(Oid *) palloc(numSortCols * sizeof(Oid));
peraggstate->sortNullsFirst =
(bool *) palloc(numSortCols * sizeof(bool));
@ -1801,6 +1807,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
peraggstate->sortColIdx[i] = tle->resno;
peraggstate->sortOperators[i] = sortcl->sortop;
peraggstate->sortCollations[i] = exprCollation((Node *) tle->expr);
peraggstate->sortNullsFirst[i] = sortcl->nulls_first;
i++;
}

View File

@ -24,6 +24,7 @@
#include "executor/nodeFunctionscan.h"
#include "funcapi.h"
#include "nodes/nodeFuncs.h"
#include "utils/builtins.h"
@ -185,12 +186,16 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
funcrettype,
-1,
0);
TupleDescInitEntryCollation(tupdesc,
(AttrNumber) 1,
exprCollation(node->funcexpr));
}
else if (functypclass == TYPEFUNC_RECORD)
{
tupdesc = BuildDescFromLists(node->funccolnames,
node->funccoltypes,
node->funccoltypmods);
node->funccoltypmods,
node->funccolcollations);
}
else
{

View File

@ -732,6 +732,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
int op_strategy; /* operator's strategy number */
Oid op_lefttype; /* operator's declared input types */
Oid op_righttype;
Oid collation;
Expr *leftop; /* expr on lhs of operator */
Expr *rightop; /* expr on rhs ... */
AttrNumber varattno; /* att number used in scan */
@ -831,6 +832,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
op_righttype, /* strategy subtype */
opfuncid, /* reg proc to use */
scanvalue); /* constant */
ScanKeyEntryInitializeCollation(this_scan_key,
((OpExpr *) clause)->collid);
}
else if (IsA(clause, RowCompareExpr))
{
@ -839,6 +842,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
ListCell *largs_cell = list_head(rc->largs);
ListCell *rargs_cell = list_head(rc->rargs);
ListCell *opnos_cell = list_head(rc->opnos);
ListCell *collids_cell = list_head(rc->collids);
ScanKey first_sub_key;
int n_sub_key;
@ -897,6 +901,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
op_righttype,
BTORDER_PROC);
collation = lfirst_oid(collids_cell);
collids_cell = lnext(collids_cell);
/*
* rightop is the constant or variable comparison value
*/
@ -952,6 +959,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
op_righttype, /* strategy subtype */
opfuncid, /* reg proc to use */
scanvalue); /* constant */
ScanKeyEntryInitializeCollation(this_sub_key,
collation);
n_sub_key++;
}
@ -1035,6 +1044,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
op_righttype, /* strategy subtype */
opfuncid, /* reg proc to use */
(Datum) 0); /* constant */
ScanKeyEntryInitializeCollation(this_scan_key,
saop->collid);
}
else if (IsA(clause, NullTest))
{

View File

@ -150,6 +150,9 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
sortFunction,
(Datum) 0);
ScanKeyEntryInitializeCollation(&mergestate->ms_scankeys[i],
node->collations[i]);
/* However, we use btree's conventions for encoding directionality */
if (reverse)
mergestate->ms_scankeys[i].sk_flags |= SK_BT_DESC;

View File

@ -180,6 +180,7 @@ typedef enum
static MergeJoinClause
MJExamineQuals(List *mergeclauses,
Oid *mergefamilies,
Oid *mergecollations,
int *mergestrategies,
bool *mergenullsfirst,
PlanState *parent)
@ -197,6 +198,7 @@ MJExamineQuals(List *mergeclauses,
OpExpr *qual = (OpExpr *) lfirst(cl);
MergeJoinClause clause = &clauses[iClause];
Oid opfamily = mergefamilies[iClause];
Oid collation = mergecollations[iClause];
StrategyNumber opstrategy = mergestrategies[iClause];
bool nulls_first = mergenullsfirst[iClause];
int op_strategy;
@ -240,6 +242,7 @@ MJExamineQuals(List *mergeclauses,
/* Set up the fmgr lookup information */
fmgr_info(cmpproc, &(clause->cmpfinfo));
fmgr_info_collation(collation, &(clause->cmpfinfo));
/* Fill the additional comparison-strategy flags */
if (opstrategy == BTLessStrategyNumber)
@ -1636,6 +1639,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate->mj_NumClauses = list_length(node->mergeclauses);
mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
node->mergeFamilies,
node->mergeCollations,
node->mergeStrategies,
node->mergeNullsFirst,
(PlanState *) mergestate);

View File

@ -86,6 +86,7 @@ ExecSort(SortState *node)
plannode->numCols,
plannode->sortColIdx,
plannode->sortOperators,
plannode->collations,
plannode->nullsFirst,
work_mem,
node->randomAccess);

View File

@ -831,7 +831,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
/* Lookup the equality function (potentially cross-type) */
fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
sstate->cur_eq_funcs[i - 1].fn_expr = (Node *) opexpr;
fmgr_info_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
/* Look up the equality function for the RHS type */
if (!get_compatible_hash_operators(opexpr->opno,

View File

@ -1561,7 +1561,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo,
econtext->ecxt_per_query_memory);
perfuncstate->flinfo.fn_expr = (Node *) wfunc;
fmgr_info_expr((Node *) wfunc, &perfuncstate->flinfo);
get_typlenbyval(wfunc->wintype,
&perfuncstate->resulttypeLen,
&perfuncstate->resulttypeByVal);
@ -1794,16 +1794,17 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
wfunc->wintype,
transfn_oid,
finalfn_oid,
wfunc->collid,
&transfnexpr,
&finalfnexpr);
fmgr_info(transfn_oid, &peraggstate->transfn);
peraggstate->transfn.fn_expr = (Node *) transfnexpr;
fmgr_info_expr((Node *) transfnexpr, &peraggstate->transfn);
if (OidIsValid(finalfn_oid))
{
fmgr_info(finalfn_oid, &peraggstate->finalfn);
peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
fmgr_info_expr((Node *) finalfnexpr, &peraggstate->finalfn);
}
get_typlenbyval(wfunc->wintype,