1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +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

@ -1795,6 +1795,7 @@ cost_mergejoin(MergePath *path, PlannerInfo *root, SpecialJoinInfo *sjinfo)
ipathkey = (PathKey *) linitial(ipathkeys);
/* debugging check */
if (opathkey->pk_opfamily != ipathkey->pk_opfamily ||
opathkey->pk_collation != ipathkey->pk_collation ||
opathkey->pk_strategy != ipathkey->pk_strategy ||
opathkey->pk_nulls_first != ipathkey->pk_nulls_first)
elog(ERROR, "left and right pathkeys do not match in mergejoin");
@ -2045,6 +2046,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
{
cache = (MergeScanSelCache *) lfirst(lc);
if (cache->opfamily == pathkey->pk_opfamily &&
cache->collation == pathkey->pk_collation &&
cache->strategy == pathkey->pk_strategy &&
cache->nulls_first == pathkey->pk_nulls_first)
return cache;
@ -2054,6 +2056,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
mergejoinscansel(root,
(Node *) rinfo->clause,
pathkey->pk_opfamily,
pathkey->pk_collation,
pathkey->pk_strategy,
pathkey->pk_nulls_first,
&leftstartsel,
@ -2066,6 +2069,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
cache = (MergeScanSelCache *) palloc(sizeof(MergeScanSelCache));
cache->opfamily = pathkey->pk_opfamily;
cache->collation = pathkey->pk_collation;
cache->strategy = pathkey->pk_strategy;
cache->nulls_first = pathkey->pk_nulls_first;
cache->leftstartsel = leftstartsel;

View File

@ -23,6 +23,7 @@
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
@ -99,15 +100,15 @@ static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
Relids outer_relids, bool isouterjoin);
static bool match_boolean_index_clause(Node *clause, int indexcol,
IndexOptInfo *index);
static bool match_special_index_operator(Expr *clause, Oid opfamily,
static bool match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily,
bool indexkey_on_left);
static Expr *expand_boolean_index_clause(Node *clause, int indexcol,
IndexOptInfo *index);
static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily);
static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation);
static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo,
IndexOptInfo *index,
int indexcol);
static List *prefix_quals(Node *leftop, Oid opfamily,
static List *prefix_quals(Node *leftop, Oid opfamily, Oid collation,
Const *prefix, Pattern_Prefix_Status pstatus);
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily,
Datum rightop);
@ -1142,7 +1143,9 @@ group_clauses_by_indexkey(IndexOptInfo *index,
* and
* (2) must contain an operator which is in the same family as the index
* operator for this column, or is a "special" operator as recognized
* by match_special_index_operator().
* by match_special_index_operator();
* and
* (3) must match the collation of the index.
*
* Our definition of "const" is pretty liberal: we allow Vars belonging
* to the caller-specified outer_relids relations (which had better not
@ -1198,6 +1201,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
SaOpControl saop_control)
{
Expr *clause = rinfo->clause;
Oid collation = index->indexcollations[indexcol];
Oid opfamily = index->opfamily[indexcol];
Node *leftop,
*rightop;
@ -1280,7 +1284,8 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(right_relids, outer_relids) &&
!contain_volatile_functions(rightop))
{
if (is_indexable_operator(expr_op, opfamily, true))
if (is_indexable_operator(expr_op, opfamily, true) &&
(!collation || collation == exprCollation((Node *) clause)))
return true;
/*
@ -1288,7 +1293,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
* is a "special" indexable operator.
*/
if (plain_op &&
match_special_index_operator(clause, opfamily, true))
match_special_index_operator(clause, collation, opfamily, true))
return true;
return false;
}
@ -1298,14 +1303,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(left_relids, outer_relids) &&
!contain_volatile_functions(leftop))
{
if (is_indexable_operator(expr_op, opfamily, false))
if (is_indexable_operator(expr_op, opfamily, false) &&
(!collation || collation == exprCollation((Node *) clause)))
return true;
/*
* If we didn't find a member of the index's opfamily, see whether it
* is a "special" indexable operator.
*/
if (match_special_index_operator(clause, opfamily, false))
if (match_special_index_operator(clause, collation, opfamily, false))
return true;
return false;
}
@ -1391,6 +1397,9 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
else
return false;
if (index->indexcollations[indexcol] != linitial_oid(clause->collids))
return false;
/* We're good if the operator is the right type of opfamily member */
switch (get_op_opfamily_strategy(expr_op, opfamily))
{
@ -2380,7 +2389,7 @@ match_boolean_index_clause(Node *clause,
* Return 'true' if we can do something with it anyway.
*/
static bool
match_special_index_operator(Expr *clause, Oid opfamily,
match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily,
bool indexkey_on_left)
{
bool isIndexable = false;
@ -2495,7 +2504,7 @@ match_special_index_operator(Expr *clause, Oid opfamily,
isIndexable =
(opfamily == TEXT_PATTERN_BTREE_FAM_OID) ||
(opfamily == TEXT_BTREE_FAM_OID &&
(pstatus == Pattern_Prefix_Exact || lc_collate_is_c()));
(pstatus == Pattern_Prefix_Exact || lc_collate_is_c(idxcolcollation)));
break;
case OID_BPCHAR_LIKE_OP:
@ -2505,7 +2514,7 @@ match_special_index_operator(Expr *clause, Oid opfamily,
isIndexable =
(opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) ||
(opfamily == BPCHAR_BTREE_FAM_OID &&
(pstatus == Pattern_Prefix_Exact || lc_collate_is_c()));
(pstatus == Pattern_Prefix_Exact || lc_collate_is_c(idxcolcollation)));
break;
case OID_NAME_LIKE_OP:
@ -2526,6 +2535,25 @@ match_special_index_operator(Expr *clause, Oid opfamily,
break;
}
if (!isIndexable)
return false;
/*
* For case-insensitive matching, we also need to check that the
* collations match.
*/
switch (expr_op)
{
case OID_TEXT_ICLIKE_OP:
case OID_TEXT_ICREGEXEQ_OP:
case OID_BPCHAR_ICLIKE_OP:
case OID_BPCHAR_ICREGEXEQ_OP:
case OID_NAME_ICLIKE_OP:
case OID_NAME_ICREGEXEQ_OP:
isIndexable = (idxcolcollation == exprCollation((Node *) clause));
break;
}
return isIndexable;
}
@ -2561,6 +2589,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{
List *clausegroup = (List *) lfirst(lc);
Oid curFamily = index->opfamily[indexcol];
Oid curCollation = index->indexcollations[indexcol];
ListCell *lc2;
foreach(lc2, clausegroup)
@ -2592,7 +2621,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{
resultquals = list_concat(resultquals,
expand_indexqual_opclause(rinfo,
curFamily));
curFamily,
curCollation));
}
else if (IsA(clause, ScalarArrayOpExpr))
{
@ -2693,7 +2723,7 @@ expand_boolean_index_clause(Node *clause,
* expand special cases that were accepted by match_special_index_operator().
*/
static List *
expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation)
{
Expr *clause = rinfo->clause;
@ -2724,7 +2754,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
{
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
&prefix, &rest);
return prefix_quals(leftop, opfamily, prefix, pstatus);
return prefix_quals(leftop, opfamily, collation, prefix, pstatus);
}
break;
@ -2736,7 +2766,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
&prefix, &rest);
return prefix_quals(leftop, opfamily, prefix, pstatus);
return prefix_quals(leftop, opfamily, collation, prefix, pstatus);
}
break;
@ -2748,7 +2778,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
&prefix, &rest);
return prefix_quals(leftop, opfamily, prefix, pstatus);
return prefix_quals(leftop, opfamily, collation, prefix, pstatus);
}
break;
@ -2760,7 +2790,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
&prefix, &rest);
return prefix_quals(leftop, opfamily, prefix, pstatus);
return prefix_quals(leftop, opfamily, collation, prefix, pstatus);
}
break;
@ -2814,6 +2844,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
ListCell *largs_cell;
ListCell *rargs_cell;
ListCell *opnos_cell;
ListCell *collids_cell;
/* We have to figure out (again) how the first col matches */
var_on_left = match_index_to_operand((Node *) linitial(clause->largs),
@ -2845,6 +2876,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
largs_cell = lnext(list_head(clause->largs));
rargs_cell = lnext(list_head(clause->rargs));
opnos_cell = lnext(list_head(clause->opnos));
collids_cell = lnext(list_head(clause->collids));
while (largs_cell != NULL)
{
@ -2891,6 +2923,10 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
!= op_strategy)
break;
/* Does collation match? */
if (lfirst_oid(collids_cell) != index->indexcollations[i])
break;
/* Add opfamily and datatypes to lists */
get_op_opfamily_properties(expr_op, index->opfamily[i], false,
&op_strategy,
@ -2974,6 +3010,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
rc->opnos = new_ops;
rc->opfamilies = list_truncate(list_copy(clause->opfamilies),
matching_cols);
rc->collids = list_truncate(list_copy(clause->collids),
matching_cols);
rc->largs = list_truncate((List *) copyObject(clause->largs),
matching_cols);
rc->rargs = list_truncate((List *) copyObject(clause->rargs),
@ -2998,7 +3036,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
* operators and operand datatypes.
*/
static List *
prefix_quals(Node *leftop, Oid opfamily,
prefix_quals(Node *leftop, Oid opfamily, Oid collation,
Const *prefix_const, Pattern_Prefix_Status pstatus)
{
List *result;
@ -3100,6 +3138,7 @@ prefix_quals(Node *leftop, Oid opfamily,
if (oproid == InvalidOid)
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(oproid), &ltproc);
fmgr_info_collation(collation, &ltproc);
greaterstr = make_greater_string(prefix_const, &ltproc);
if (greaterstr)
{

View File

@ -18,6 +18,7 @@
#include "postgres.h"
#include "access/skey.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@ -30,10 +31,10 @@
#include "utils/lsyscache.h"
static PathKey *makePathKey(EquivalenceClass *eclass, Oid opfamily,
static PathKey *makePathKey(EquivalenceClass *eclass, Oid opfamily, Oid collation,
int strategy, bool nulls_first);
static PathKey *make_canonical_pathkey(PlannerInfo *root,
EquivalenceClass *eclass, Oid opfamily,
EquivalenceClass *eclass, Oid opfamily, Oid collation,
int strategy, bool nulls_first);
static bool pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys);
static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel,
@ -53,13 +54,14 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey);
* convenience routine to build the specified node.
*/
static PathKey *
makePathKey(EquivalenceClass *eclass, Oid opfamily,
makePathKey(EquivalenceClass *eclass, Oid opfamily, Oid collation,
int strategy, bool nulls_first)
{
PathKey *pk = makeNode(PathKey);
pk->pk_eclass = eclass;
pk->pk_opfamily = opfamily;
pk->pk_collation = collation;
pk->pk_strategy = strategy;
pk->pk_nulls_first = nulls_first;
@ -77,7 +79,7 @@ makePathKey(EquivalenceClass *eclass, Oid opfamily,
*/
static PathKey *
make_canonical_pathkey(PlannerInfo *root,
EquivalenceClass *eclass, Oid opfamily,
EquivalenceClass *eclass, Oid opfamily, Oid collation,
int strategy, bool nulls_first)
{
PathKey *pk;
@ -93,6 +95,7 @@ make_canonical_pathkey(PlannerInfo *root,
pk = (PathKey *) lfirst(lc);
if (eclass == pk->pk_eclass &&
opfamily == pk->pk_opfamily &&
collation == pk->pk_collation &&
strategy == pk->pk_strategy &&
nulls_first == pk->pk_nulls_first)
return pk;
@ -104,7 +107,7 @@ make_canonical_pathkey(PlannerInfo *root,
*/
oldcontext = MemoryContextSwitchTo(root->planner_cxt);
pk = makePathKey(eclass, opfamily, strategy, nulls_first);
pk = makePathKey(eclass, opfamily, collation, strategy, nulls_first);
root->canon_pathkeys = lappend(root->canon_pathkeys, pk);
MemoryContextSwitchTo(oldcontext);
@ -206,6 +209,7 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
cpathkey = make_canonical_pathkey(root,
eclass,
pathkey->pk_opfamily,
pathkey->pk_collation,
pathkey->pk_strategy,
pathkey->pk_nulls_first);
@ -247,6 +251,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
Oid equality_op;
List *opfamilies;
EquivalenceClass *eclass;
Oid collation;
strategy = reverse_sort ? BTGreaterStrategyNumber : BTLessStrategyNumber;
@ -301,12 +306,14 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
if (!eclass)
return NULL;
collation = exprCollation((Node *) expr);
/* And finally we can find or create a PathKey node */
if (canonicalize)
return make_canonical_pathkey(root, eclass, opfamily,
return make_canonical_pathkey(root, eclass, opfamily, collation,
strategy, nulls_first);
else
return makePathKey(eclass, opfamily, strategy, nulls_first);
return makePathKey(eclass, opfamily, collation, strategy, nulls_first);
}
/*
@ -605,7 +612,8 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno)
ListCell *temp;
Index relid;
Oid reloid,
vartypeid;
vartypeid,
varcollid;
int32 type_mod;
foreach(temp, rel->reltargetlist)
@ -620,8 +628,9 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno)
relid = rel->relid;
reloid = getrelid(relid, root->parse->rtable);
get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);
varcollid = get_attcollation(reloid, varattno);
return makeVar(relid, varattno, vartypeid, type_mod, 0);
return makeVar(relid, varattno, vartypeid, type_mod, varcollid, 0);
}
/*
@ -703,6 +712,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
make_canonical_pathkey(root,
outer_ec,
sub_pathkey->pk_opfamily,
sub_pathkey->pk_collation,
sub_pathkey->pk_strategy,
sub_pathkey->pk_nulls_first);
}
@ -805,6 +815,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
outer_pk = make_canonical_pathkey(root,
outer_ec,
sub_pathkey->pk_opfamily,
sub_pathkey->pk_collation,
sub_pathkey->pk_strategy,
sub_pathkey->pk_nulls_first);
/* score = # of equivalence peers */
@ -1326,6 +1337,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
pathkey = make_canonical_pathkey(root,
ec,
linitial_oid(ec->ec_opfamilies),
DEFAULT_COLLATION_OID,
BTLessStrategyNumber,
false);
/* can't be redundant because no duplicate ECs */
@ -1419,6 +1431,7 @@ make_inner_pathkeys_for_merge(PlannerInfo *root,
pathkey = make_canonical_pathkey(root,
ieclass,
opathkey->pk_opfamily,
opathkey->pk_collation,
opathkey->pk_strategy,
opathkey->pk_nulls_first);
@ -1539,6 +1552,7 @@ right_merge_direction(PlannerInfo *root, PathKey *pathkey)
PathKey *query_pathkey = (PathKey *) lfirst(l);
if (pathkey->pk_eclass == query_pathkey->pk_eclass &&
pathkey->pk_collation == query_pathkey->pk_collation &&
pathkey->pk_opfamily == query_pathkey->pk_opfamily)
{
/*

View File

@ -105,7 +105,7 @@ static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tidquals);
static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
Index scanrelid, Node *funcexpr, List *funccolnames,
List *funccoltypes, List *funccoltypmods);
List *funccoltypes, List *funccoltypmods, List *funccolcollations);
static ValuesScan *make_valuesscan(List *qptlist, List *qpqual,
Index scanrelid, List *values_lists);
static CteScan *make_ctescan(List *qptlist, List *qpqual,
@ -133,12 +133,13 @@ static MergeJoin *make_mergejoin(List *tlist,
List *joinclauses, List *otherclauses,
List *mergeclauses,
Oid *mergefamilies,
Oid *mergecollations,
int *mergestrategies,
bool *mergenullsfirst,
Plan *lefttree, Plan *righttree,
JoinType jointype);
static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
AttrNumber *sortColIdx, Oid *sortOperators, bool *nullsFirst,
AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst,
double limit_tuples);
static Plan *prepare_sort_from_pathkeys(PlannerInfo *root,
Plan *lefttree, List *pathkeys,
@ -146,6 +147,7 @@ static Plan *prepare_sort_from_pathkeys(PlannerInfo *root,
int *p_numsortkeys,
AttrNumber **p_sortColIdx,
Oid **p_sortOperators,
Oid **p_collations,
bool **p_nullsFirst);
static Material *make_material(Plan *lefttree);
@ -671,6 +673,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
&node->numCols,
&node->sortColIdx,
&node->sortOperators,
&node->collations,
&node->nullsFirst);
/*
@ -685,6 +688,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/* Build the child plan */
@ -696,6 +700,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
&numsortkeys,
&sortColIdx,
&sortOperators,
&collations,
&nullsFirst);
/*
@ -710,13 +715,15 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
elog(ERROR, "MergeAppend child's targetlist doesn't match MergeAppend");
Assert(memcmp(sortOperators, node->sortOperators,
numsortkeys * sizeof(Oid)) == 0);
Assert(memcmp(collations, node->collations,
numsortkeys * sizeof(Oid)) == 0);
Assert(memcmp(nullsFirst, node->nullsFirst,
numsortkeys * sizeof(bool)) == 0);
/* Now, insert a Sort node if subplan isn't sufficiently ordered */
if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
subplan = (Plan *) make_sort(root, subplan, numsortkeys,
sortColIdx, sortOperators, nullsFirst,
sortColIdx, sortOperators, collations, nullsFirst,
best_path->limit_tuples);
subplans = lappend(subplans, subplan);
@ -1569,7 +1576,8 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path,
rte->funcexpr,
rte->eref->colnames,
rte->funccoltypes,
rte->funccoltypmods);
rte->funccoltypmods,
rte->funccolcollations);
copy_path_costsize(&scan_plan->scan.plan, best_path);
@ -1847,6 +1855,7 @@ create_mergejoin_plan(PlannerInfo *root,
List *innerpathkeys;
int nClauses;
Oid *mergefamilies;
Oid *mergecollations;
int *mergestrategies;
bool *mergenullsfirst;
MergeJoin *join_plan;
@ -1946,6 +1955,7 @@ create_mergejoin_plan(PlannerInfo *root,
nClauses = list_length(mergeclauses);
Assert(nClauses == list_length(best_path->path_mergeclauses));
mergefamilies = (Oid *) palloc(nClauses * sizeof(Oid));
mergecollations = (Oid *) palloc(nClauses * sizeof(Oid));
mergestrategies = (int *) palloc(nClauses * sizeof(int));
mergenullsfirst = (bool *) palloc(nClauses * sizeof(bool));
@ -2074,12 +2084,14 @@ create_mergejoin_plan(PlannerInfo *root,
/* pathkeys should match each other too (more debugging) */
if (opathkey->pk_opfamily != ipathkey->pk_opfamily ||
opathkey->pk_collation != ipathkey->pk_collation ||
opathkey->pk_strategy != ipathkey->pk_strategy ||
opathkey->pk_nulls_first != ipathkey->pk_nulls_first)
elog(ERROR, "left and right pathkeys do not match in mergejoin");
/* OK, save info for executor */
mergefamilies[i] = opathkey->pk_opfamily;
mergecollations[i] = opathkey->pk_collation;
mergestrategies[i] = opathkey->pk_strategy;
mergenullsfirst[i] = opathkey->pk_nulls_first;
i++;
@ -2099,6 +2111,7 @@ create_mergejoin_plan(PlannerInfo *root,
otherclauses,
mergeclauses,
mergefamilies,
mergecollations,
mergestrategies,
mergenullsfirst,
outer_plan,
@ -2528,6 +2541,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index)
/* Found a match */
result = makeVar(index->rel->relid, pos + 1,
exprType(lfirst(indexpr_item)), -1,
exprCollation(lfirst(indexpr_item)),
0);
return (Node *) result;
}
@ -2881,7 +2895,8 @@ make_functionscan(List *qptlist,
Node *funcexpr,
List *funccolnames,
List *funccoltypes,
List *funccoltypmods)
List *funccoltypmods,
List *funccolcollations)
{
FunctionScan *node = makeNode(FunctionScan);
Plan *plan = &node->scan.plan;
@ -2896,6 +2911,7 @@ make_functionscan(List *qptlist,
node->funccolnames = funccolnames;
node->funccoltypes = funccoltypes;
node->funccoltypmods = funccoltypmods;
node->funccolcollations = funccolcollations;
return node;
}
@ -3181,6 +3197,7 @@ make_mergejoin(List *tlist,
List *otherclauses,
List *mergeclauses,
Oid *mergefamilies,
Oid *mergecollations,
int *mergestrategies,
bool *mergenullsfirst,
Plan *lefttree,
@ -3197,6 +3214,7 @@ make_mergejoin(List *tlist,
plan->righttree = righttree;
node->mergeclauses = mergeclauses;
node->mergeFamilies = mergefamilies;
node->mergeCollations = mergecollations;
node->mergeStrategies = mergestrategies;
node->mergeNullsFirst = mergenullsfirst;
node->join.jointype = jointype;
@ -3214,7 +3232,7 @@ make_mergejoin(List *tlist,
*/
static Sort *
make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
AttrNumber *sortColIdx, Oid *sortOperators, bool *nullsFirst,
AttrNumber *sortColIdx, Oid *sortOperators, Oid *collations, bool *nullsFirst,
double limit_tuples)
{
Sort *node = makeNode(Sort);
@ -3238,6 +3256,7 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
node->numCols = numCols;
node->sortColIdx = sortColIdx;
node->sortOperators = sortOperators;
node->collations = collations;
node->nullsFirst = nullsFirst;
return node;
@ -3253,9 +3272,9 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
* max possible number of columns. Return value is the new column count.
*/
static int
add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first,
add_sort_column(AttrNumber colIdx, Oid sortOp, Oid coll, bool nulls_first,
int numCols, AttrNumber *sortColIdx,
Oid *sortOperators, bool *nullsFirst)
Oid *sortOperators, Oid *collations, bool *nullsFirst)
{
int i;
@ -3271,7 +3290,8 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first,
* opposite nulls direction is redundant.
*/
if (sortColIdx[i] == colIdx &&
sortOperators[numCols] == sortOp)
sortOperators[numCols] == sortOp &&
collations[numCols] == coll)
{
/* Already sorting by this col, so extra sort key is useless */
return numCols;
@ -3281,6 +3301,7 @@ add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first,
/* Add the column */
sortColIdx[numCols] = colIdx;
sortOperators[numCols] = sortOp;
collations[numCols] = coll;
nullsFirst[numCols] = nulls_first;
return numCols + 1;
}
@ -3320,6 +3341,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
int *p_numsortkeys,
AttrNumber **p_sortColIdx,
Oid **p_sortOperators,
Oid **p_collations,
bool **p_nullsFirst)
{
List *tlist = lefttree->targetlist;
@ -3327,6 +3349,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/*
@ -3335,6 +3358,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
numsortkeys = list_length(pathkeys);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
@ -3493,9 +3517,10 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
*/
numsortkeys = add_sort_column(tle->resno,
sortop,
pathkey->pk_collation,
pathkey->pk_nulls_first,
numsortkeys,
sortColIdx, sortOperators, nullsFirst);
sortColIdx, sortOperators, collations, nullsFirst);
}
Assert(numsortkeys > 0);
@ -3504,6 +3529,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
*p_numsortkeys = numsortkeys;
*p_sortColIdx = sortColIdx;
*p_sortOperators = sortOperators;
*p_collations = collations;
*p_nullsFirst = nullsFirst;
return lefttree;
@ -3525,6 +3551,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/* Compute sort column info, and adjust lefttree as needed */
@ -3533,11 +3560,12 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
&numsortkeys,
&sortColIdx,
&sortOperators,
&collations,
&nullsFirst);
/* Now build the Sort node */
return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, nullsFirst, limit_tuples);
sortColIdx, sortOperators, collations, nullsFirst, limit_tuples);
}
/*
@ -3555,6 +3583,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/*
@ -3563,6 +3592,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
numsortkeys = list_length(sortcls);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
@ -3578,15 +3608,16 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
* redundantly.
*/
numsortkeys = add_sort_column(tle->resno, sortcl->sortop,
exprCollation((Node *) tle->expr),
sortcl->nulls_first,
numsortkeys,
sortColIdx, sortOperators, nullsFirst);
sortColIdx, sortOperators, collations, nullsFirst);
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, nullsFirst, -1.0);
sortColIdx, sortOperators, collations, nullsFirst, -1.0);
}
/*
@ -3614,6 +3645,7 @@ make_sort_from_groupcols(PlannerInfo *root,
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/*
@ -3622,6 +3654,7 @@ make_sort_from_groupcols(PlannerInfo *root,
numsortkeys = list_length(groupcls);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
@ -3637,16 +3670,17 @@ make_sort_from_groupcols(PlannerInfo *root,
* redundantly.
*/
numsortkeys = add_sort_column(tle->resno, grpcl->sortop,
exprCollation((Node *) tle->expr),
grpcl->nulls_first,
numsortkeys,
sortColIdx, sortOperators, nullsFirst);
sortColIdx, sortOperators, collations, nullsFirst);
grpno++;
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, nullsFirst, -1.0);
sortColIdx, sortOperators, collations, nullsFirst, -1.0);
}
static Material *

View File

@ -561,7 +561,8 @@ make_agg_subplan(PlannerInfo *root, RelOptInfo *rel, PrivateMMAggInfo *info)
*/
info->param = SS_make_initplan_from_plan(&subroot, plan,
exprType((Node *) tle->expr),
-1);
-1,
exprCollation((Node *) tle->expr));
/*
* Put the updated list of InitPlans back into the outer PlannerInfo.

View File

@ -213,9 +213,11 @@ set_plan_references(PlannerGlobal *glob, Plan *plan,
newrte->funcexpr = NULL;
newrte->funccoltypes = NIL;
newrte->funccoltypmods = NIL;
newrte->funccolcollations = NIL;
newrte->values_lists = NIL;
newrte->ctecoltypes = NIL;
newrte->ctecoltypmods = NIL;
newrte->ctecolcollations = NIL;
glob->finalrtable = lappend(glob->finalrtable, newrte);
@ -1119,6 +1121,7 @@ set_dummy_tlist_references(Plan *plan, int rtoffset)
tle->resno,
exprType((Node *) oldvar),
exprTypmod((Node *) oldvar),
exprCollation((Node *) oldvar),
0);
if (IsA(oldvar, Var))
{

View File

@ -157,6 +157,7 @@ replace_outer_var(PlannerInfo *root, Var *var)
retval->paramid = i;
retval->paramtype = var->vartype;
retval->paramtypmod = var->vartypmod;
retval->paramcollation = var->varcollid;
retval->location = -1;
return retval;
@ -185,6 +186,7 @@ assign_nestloop_param(PlannerInfo *root, Var *var)
retval->paramid = i;
retval->paramtype = var->vartype;
retval->paramtypmod = var->vartypmod;
retval->paramcollation = var->varcollid;
retval->location = -1;
return retval;
@ -225,6 +227,7 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg)
retval->paramid = i;
retval->paramtype = agg->aggtype;
retval->paramtypmod = -1;
retval->paramcollation = agg->collid;
retval->location = -1;
return retval;
@ -236,7 +239,7 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg)
* This is used to allocate PARAM_EXEC slots for subplan outputs.
*/
static Param *
generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation)
{
Param *retval;
PlannerParamItem *pitem;
@ -246,6 +249,7 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
retval->paramid = list_length(root->glob->paramlist);
retval->paramtype = paramtype;
retval->paramtypmod = paramtypmod;
retval->paramcollation = paramcollation;
retval->location = -1;
pitem = makeNode(PlannerParamItem);
@ -270,7 +274,7 @@ SS_assign_special_param(PlannerInfo *root)
Param *param;
/* We generate a Param of datatype INTERNAL */
param = generate_new_param(root, INTERNALOID, -1);
param = generate_new_param(root, INTERNALOID, -1, InvalidOid);
/* ... but the caller only cares about its ID */
return param->paramid;
}
@ -278,13 +282,13 @@ SS_assign_special_param(PlannerInfo *root)
/*
* Get the datatype of the first column of the plan's output.
*
* This is stored for ARRAY_SUBLINK execution and for exprType()/exprTypmod(),
* This is stored for ARRAY_SUBLINK execution and for exprType()/exprTypmod()/exprCollation(),
* which have no way to get at the plan associated with a SubPlan node.
* We really only need the info for EXPR_SUBLINK and ARRAY_SUBLINK subplans,
* but for consistency we save it always.
*/
static void
get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod)
get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod, Oid *colcollation)
{
/* In cases such as EXISTS, tlist might be empty; arbitrarily use VOID */
if (plan->targetlist)
@ -296,11 +300,13 @@ get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod)
{
*coltype = exprType((Node *) tent->expr);
*coltypmod = exprTypmod((Node *) tent->expr);
*colcollation = exprCollation((Node *) tent->expr);
return;
}
}
*coltype = VOIDOID;
*coltypmod = -1;
*colcollation = InvalidOid;
}
/*
@ -470,7 +476,7 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
splan->subLinkType = subLinkType;
splan->testexpr = NULL;
splan->paramIds = NIL;
get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod);
get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod, &splan->firstColCollation);
splan->useHashTable = false;
splan->unknownEqFalse = unknownEqFalse;
splan->setParam = NIL;
@ -523,7 +529,7 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
Param *prm;
Assert(testexpr == NULL);
prm = generate_new_param(root, BOOLOID, -1);
prm = generate_new_param(root, BOOLOID, -1, InvalidOid);
splan->setParam = list_make1_int(prm->paramid);
isInitPlan = true;
result = (Node *) prm;
@ -537,7 +543,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
Assert(testexpr == NULL);
prm = generate_new_param(root,
exprType((Node *) te->expr),
exprTypmod((Node *) te->expr));
exprTypmod((Node *) te->expr),
exprCollation((Node *) te->expr));
splan->setParam = list_make1_int(prm->paramid);
isInitPlan = true;
result = (Node *) prm;
@ -556,7 +563,8 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks,
format_type_be(exprType((Node *) te->expr)));
prm = generate_new_param(root,
arraytype,
exprTypmod((Node *) te->expr));
exprTypmod((Node *) te->expr),
exprCollation((Node *) te->expr));
splan->setParam = list_make1_int(prm->paramid);
isInitPlan = true;
result = (Node *) prm;
@ -708,7 +716,8 @@ generate_subquery_params(PlannerInfo *root, List *tlist, List **paramIds)
param = generate_new_param(root,
exprType((Node *) tent->expr),
exprTypmod((Node *) tent->expr));
exprTypmod((Node *) tent->expr),
exprCollation((Node *) tent->expr));
result = lappend(result, param);
ids = lappend_int(ids, param->paramid);
}
@ -964,7 +973,7 @@ SS_process_ctes(PlannerInfo *root)
splan->subLinkType = CTE_SUBLINK;
splan->testexpr = NULL;
splan->paramIds = NIL;
get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod);
get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod, &splan->firstColCollation);
splan->useHashTable = false;
splan->unknownEqFalse = false;
splan->setParam = NIL;
@ -999,7 +1008,7 @@ SS_process_ctes(PlannerInfo *root)
* Assign a param to represent the query output. We only really care
* about reserving a parameter ID number.
*/
prm = generate_new_param(root, INTERNALOID, -1);
prm = generate_new_param(root, INTERNALOID, -1, InvalidOid);
splan->setParam = list_make1_int(prm->paramid);
/*
@ -1565,7 +1574,8 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
oc = lnext(oc);
param = generate_new_param(root,
exprType(rightarg),
exprTypmod(rightarg));
exprTypmod(rightarg),
exprCollation(rightarg));
tlist = lappend(tlist,
makeTargetEntry((Expr *) rightarg,
resno++,
@ -2352,7 +2362,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
*/
Param *
SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
Oid resulttype, int32 resulttypmod)
Oid resulttype, int32 resulttypmod, Oid resultcollation)
{
SubPlan *node;
Param *prm;
@ -2388,7 +2398,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
*/
node = makeNode(SubPlan);
node->subLinkType = EXPR_SUBLINK;
get_first_col_type(plan, &node->firstColType, &node->firstColTypmod);
get_first_col_type(plan, &node->firstColType, &node->firstColTypmod, &node->firstColCollation);
node->plan_id = list_length(root->glob->subplans);
root->init_plans = lappend(root->init_plans, node);
@ -2403,7 +2413,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
/*
* Make a Param that will be the subplan's output.
*/
prm = generate_new_param(root, resulttype, resulttypmod);
prm = generate_new_param(root, resulttype, resulttypmod, resultcollation);
node->setParam = list_make1_int(prm->paramid);
/* Label the subplan for EXPLAIN purposes */

View File

@ -445,6 +445,7 @@ inline_set_returning_functions(PlannerInfo *root)
rte->funcexpr = NULL;
rte->funccoltypes = NIL;
rte->funccoltypmods = NIL;
rte->funccolcollations = NIL;
}
}
}

View File

@ -100,6 +100,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
SelfItemPointerAttributeNumber,
TIDOID,
-1,
InvalidOid,
0);
snprintf(resname, sizeof(resname), "ctid%u", rc->rti);
tle = makeTargetEntry((Expr *) var,
@ -115,6 +116,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
TableOidAttributeNumber,
OIDOID,
-1,
InvalidOid,
0);
snprintf(resname, sizeof(resname), "tableoid%u", rc->rti);
tle = makeTargetEntry((Expr *) var,
@ -257,6 +259,7 @@ expand_targetlist(List *tlist, int command_type,
*/
Oid atttype = att_tup->atttypid;
int32 atttypmod = att_tup->atttypmod;
Oid attcollation = att_tup->attcollation;
Node *new_expr;
switch (command_type)
@ -296,6 +299,7 @@ expand_targetlist(List *tlist, int command_type,
attrno,
atttype,
atttypmod,
attcollation,
0);
}
else

View File

@ -86,7 +86,7 @@ static List *generate_setop_tlist(List *colTypes, int flag,
bool hack_constants,
List *input_tlist,
List *refnames_tlist);
static List *generate_append_tlist(List *colTypes, bool flag,
static List *generate_append_tlist(List *colTypes, List *colCollations, bool flag,
List *input_plans,
List *refnames_tlist);
static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
@ -348,7 +348,7 @@ generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
/*
* Generate tlist for RecursiveUnion plan node --- same as in Append cases
*/
tlist = generate_append_tlist(setOp->colTypes, false,
tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
list_make2(lplan, rplan),
refnames_tlist);
@ -443,7 +443,7 @@ generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
* concerned, but we must make it look real anyway for the benefit of the
* next plan level up.
*/
tlist = generate_append_tlist(op->colTypes, false,
tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
planlist, refnames_tlist);
/*
@ -534,7 +534,7 @@ generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
* column is shown as a variable not a constant, else setrefs.c will get
* confused.
*/
tlist = generate_append_tlist(op->colTypes, true,
tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
planlist, refnames_tlist);
/*
@ -885,6 +885,7 @@ generate_setop_tlist(List *colTypes, int flag,
inputtle->resno,
exprType((Node *) inputtle->expr),
exprTypmod((Node *) inputtle->expr),
exprCollation((Node *) inputtle->expr),
0);
if (exprType(expr) != colType)
{
@ -936,13 +937,14 @@ generate_setop_tlist(List *colTypes, int flag,
* The Vars are always generated with varno 0.
*/
static List *
generate_append_tlist(List *colTypes, bool flag,
generate_append_tlist(List *colTypes, List*colCollations, bool flag,
List *input_plans,
List *refnames_tlist)
{
List *tlist = NIL;
int resno = 1;
ListCell *curColType;
ListCell *curColCollation;
ListCell *ref_tl_item;
int colindex;
TargetEntry *tle;
@ -997,10 +999,11 @@ generate_append_tlist(List *colTypes, bool flag,
* Now we can build the tlist for the Append.
*/
colindex = 0;
forboth(curColType, colTypes, ref_tl_item, refnames_tlist)
forthree(curColType, colTypes, curColCollation, colCollations, ref_tl_item, refnames_tlist)
{
Oid colType = lfirst_oid(curColType);
int32 colTypmod = colTypmods[colindex++];
Oid colColl = lfirst_oid(curColCollation);
TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
Assert(reftle->resno == resno);
@ -1009,6 +1012,7 @@ generate_append_tlist(List *colTypes, bool flag,
resno,
colType,
colTypmod,
colColl,
0);
tle = makeTargetEntry((Expr *) expr,
(AttrNumber) resno++,
@ -1025,6 +1029,7 @@ generate_append_tlist(List *colTypes, bool flag,
resno,
INT4OID,
-1,
InvalidOid,
0);
tle = makeTargetEntry((Expr *) expr,
(AttrNumber) resno++,
@ -1344,6 +1349,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
char *attname;
Oid atttypid;
int32 atttypmod;
Oid attcollation;
int new_attno;
att = old_tupdesc->attrs[old_attno];
@ -1356,6 +1362,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
attname = NameStr(att->attname);
atttypid = att->atttypid;
atttypmod = att->atttypmod;
attcollation = att->attcollation;
/*
* When we are generating the "translation list" for the parent table
@ -1367,6 +1374,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
(AttrNumber) (old_attno + 1),
atttypid,
atttypmod,
attcollation,
0));
continue;
}
@ -1409,6 +1417,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
(AttrNumber) (new_attno + 1),
atttypid,
atttypmod,
attcollation,
0));
}

View File

@ -100,7 +100,7 @@ static List *simplify_and_arguments(List *args,
bool *haveNull, bool *forceFalse);
static Node *simplify_boolean_equality(Oid opno, List *args);
static Expr *simplify_function(Oid funcid,
Oid result_type, int32 result_typmod, List **args,
Oid result_type, int32 result_typmod, Oid collid, List **args,
bool has_named_args,
bool allow_inline,
eval_const_expressions_context *context);
@ -114,7 +114,7 @@ static List *fetch_function_defaults(HeapTuple func_tuple);
static void recheck_cast_function_args(List *args, Oid result_type,
HeapTuple func_tuple);
static Expr *evaluate_function(Oid funcid,
Oid result_type, int32 result_typmod, List *args,
Oid result_type, int32 result_typmod, Oid collid, List *args,
HeapTuple func_tuple,
eval_const_expressions_context *context);
static Expr *inline_function(Oid funcid, Oid result_type, List *args,
@ -156,6 +156,7 @@ make_opclause(Oid opno, Oid opresulttype, bool opretset,
expr->args = list_make2(leftop, rightop);
else
expr->args = list_make1(leftop);
expr->collid = select_common_collation(NULL, expr->args, false);
expr->location = -1;
return (Expr *) expr;
}
@ -1973,7 +1974,7 @@ set_coercionform_dontcare_walker(Node *node, void *context)
*/
static bool
rowtype_field_matches(Oid rowtypeid, int fieldnum,
Oid expectedtype, int32 expectedtypmod)
Oid expectedtype, int32 expectedtypmod, Oid expectedcollation)
{
TupleDesc tupdesc;
Form_pg_attribute attr;
@ -1990,7 +1991,8 @@ rowtype_field_matches(Oid rowtypeid, int fieldnum,
attr = tupdesc->attrs[fieldnum - 1];
if (attr->attisdropped ||
attr->atttypid != expectedtype ||
attr->atttypmod != expectedtypmod)
attr->atttypmod != expectedtypmod ||
attr->attcollation != expectedcollation)
{
ReleaseTupleDesc(tupdesc);
return false;
@ -2121,6 +2123,7 @@ eval_const_expressions_mutator(Node *node,
int16 typLen;
bool typByVal;
Datum pval;
Const *cnst;
Assert(prm->ptype == param->paramtype);
get_typlenbyval(param->paramtype, &typLen, &typByVal);
@ -2128,12 +2131,14 @@ eval_const_expressions_mutator(Node *node,
pval = prm->value;
else
pval = datumCopy(prm->value, typByVal, typLen);
return (Node *) makeConst(param->paramtype,
cnst = makeConst(param->paramtype,
param->paramtypmod,
(int) typLen,
pval,
prm->isnull,
typByVal);
cnst->constcollid = param->paramcollation;
return (Node *) cnst;
}
}
}
@ -2173,6 +2178,7 @@ eval_const_expressions_mutator(Node *node,
*/
simple = simplify_function(expr->funcid,
expr->funcresulttype, exprTypmod(node),
expr->collid,
&args,
has_named_args, true, context);
if (simple) /* successfully simplified it */
@ -2190,6 +2196,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
newexpr->args = args;
newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@ -2221,6 +2228,7 @@ eval_const_expressions_mutator(Node *node,
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
expr->collid,
&args,
false, true, context);
if (simple) /* successfully simplified it */
@ -2250,6 +2258,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@ -2314,6 +2323,7 @@ eval_const_expressions_mutator(Node *node,
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
expr->collid,
&args,
false, false, context);
if (simple) /* successfully simplified it */
@ -2342,6 +2352,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@ -2493,7 +2504,7 @@ eval_const_expressions_mutator(Node *node,
getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);
simple = simplify_function(outfunc,
CSTRINGOID, -1,
CSTRINGOID, -1, InvalidOid,
&args,
false, true, context);
if (simple) /* successfully simplified output fn */
@ -2510,8 +2521,11 @@ eval_const_expressions_mutator(Node *node,
Int32GetDatum(-1),
false, true));
/* preserve collation of input expression */
simple = simplify_function(infunc,
expr->resulttype, -1,
expr->resulttype,
-1,
exprCollation((Node *) arg),
&args,
false, true, context);
if (simple) /* successfully simplified input fn */
@ -2690,6 +2704,7 @@ eval_const_expressions_mutator(Node *node,
/* Otherwise we need a new CASE node */
newcase = makeNode(CaseExpr);
newcase->casetype = caseexpr->casetype;
newcase->casecollation = caseexpr->casecollation;
newcase->arg = (Expr *) newarg;
newcase->args = newargs;
newcase->defresult = (Expr *) defresult;
@ -2782,6 +2797,7 @@ eval_const_expressions_mutator(Node *node,
newcoalesce = makeNode(CoalesceExpr);
newcoalesce->coalescetype = coalesceexpr->coalescetype;
newcoalesce->coalescecollation = coalesceexpr->coalescecollation;
newcoalesce->args = newargs;
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
@ -2811,11 +2827,13 @@ eval_const_expressions_mutator(Node *node,
if (rowtype_field_matches(((Var *) arg)->vartype,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod))
fselect->resulttypmod,
fselect->resultcollation))
return (Node *) makeVar(((Var *) arg)->varno,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
fselect->resultcollation,
((Var *) arg)->varlevelsup);
}
if (arg && IsA(arg, RowExpr))
@ -2831,9 +2849,11 @@ eval_const_expressions_mutator(Node *node,
if (rowtype_field_matches(rowexpr->row_typeid,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod) &&
fselect->resulttypmod,
fselect->resultcollation) &&
fselect->resulttype == exprType(fld) &&
fselect->resulttypmod == exprTypmod(fld))
fselect->resulttypmod == exprTypmod(fld) &&
fselect->resultcollation == exprCollation(fld))
return fld;
}
}
@ -2842,6 +2862,7 @@ eval_const_expressions_mutator(Node *node,
newfselect->fieldnum = fselect->fieldnum;
newfselect->resulttype = fselect->resulttype;
newfselect->resulttypmod = fselect->resulttypmod;
newfselect->resultcollation = fselect->resultcollation;
return (Node *) newfselect;
}
if (IsA(node, NullTest))
@ -3299,7 +3320,7 @@ simplify_boolean_equality(Oid opno, List *args)
* pass-by-reference, and it may get modified even if simplification fails.
*/
static Expr *
simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid,
List **args,
bool has_named_args,
bool allow_inline,
@ -3330,7 +3351,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
else if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args))
*args = add_function_defaults(*args, result_type, func_tuple, context);
newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
newexpr = evaluate_function(funcid, result_type, result_typmod, collid, *args,
func_tuple, context);
if (!newexpr && allow_inline)
@ -3581,7 +3602,8 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
* simplify the function.
*/
static Expr *
evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid,
List *args,
HeapTuple func_tuple,
eval_const_expressions_context *context)
{
@ -3664,6 +3686,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
newexpr->funcretset = false;
newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */
newexpr->args = args;
newexpr->collid = collid;
newexpr->location = -1;
return evaluate_expr((Expr *) newexpr, result_type, result_typmod);

View File

@ -198,10 +198,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
info->opfamily = (Oid *) palloc(sizeof(Oid) * ncolumns);
info->opcintype = (Oid *) palloc(sizeof(Oid) * ncolumns);
info->indexcollations = (Oid *) palloc(sizeof(Oid) * ncolumns);
for (i = 0; i < ncolumns; i++)
{
info->indexkeys[i] = index->indkey.values[i];
info->indexcollations[i] = indexRelation->rd_indcollation[i];
info->opfamily[i] = indexRelation->rd_opfamily[i];
info->opcintype[i] = indexRelation->rd_opcintype[i];
}
@ -634,6 +636,7 @@ get_relation_constraints(PlannerInfo *root,
i,
att->atttypid,
att->atttypmod,
att->attcollation,
0);
ntest->nulltesttype = IS_NOT_NULL;
ntest->argisrow = type_is_rowtype(att->atttypid);
@ -797,6 +800,7 @@ build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
attrno,
att_tup->atttypid,
att_tup->atttypmod,
att_tup->attcollation,
0);
tlist = lappend(tlist,

View File

@ -912,6 +912,7 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info)
state->constexpr.xpr.type = T_Const;
state->constexpr.consttype = ARR_ELEMTYPE(arrayval);
state->constexpr.consttypmod = -1;
state->constexpr.constcollid = arrayconst->constcollid;
state->constexpr.constlen = elmlen;
state->constexpr.constbyval = elmbyval;
lsecond(state->opexpr.args) = &state->constexpr;