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:
@ -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;
|
||||
|
@ -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), <proc);
|
||||
fmgr_info_collation(collation, <proc);
|
||||
greaterstr = make_greater_string(prefix_const, <proc);
|
||||
if (greaterstr)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
@ -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 *
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -445,6 +445,7 @@ inline_set_returning_functions(PlannerInfo *root)
|
||||
rte->funcexpr = NULL;
|
||||
rte->funccoltypes = NIL;
|
||||
rte->funccoltypmods = NIL;
|
||||
rte->funccolcollations = NIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user