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:
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -86,6 +86,7 @@ ExecSort(SortState *node)
|
||||
plannode->numCols,
|
||||
plannode->sortColIdx,
|
||||
plannode->sortOperators,
|
||||
plannode->collations,
|
||||
plannode->nullsFirst,
|
||||
work_mem,
|
||||
node->randomAccess);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user