aboutsummaryrefslogtreecommitdiff
path: root/src/backend/nodes/nodeFuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/nodes/nodeFuncs.c')
-rw-r--r--src/backend/nodes/nodeFuncs.c656
1 files changed, 436 insertions, 220 deletions
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 5394851a1f5..d9e5d686c25 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -79,6 +79,9 @@ exprType(Node *expr)
case T_DistinctExpr:
type = ((DistinctExpr *) expr)->opresulttype;
break;
+ case T_NullIfExpr:
+ type = ((NullIfExpr *) expr)->opresulttype;
+ break;
case T_ScalarArrayOpExpr:
type = BOOLOID;
break;
@@ -203,9 +206,6 @@ exprType(Node *expr)
else
type = XMLOID;
break;
- case T_NullIfExpr:
- type = exprType((Node *) linitial(((NullIfExpr *) expr)->args));
- break;
case T_NullTest:
type = BOOLOID;
break;
@@ -268,6 +268,17 @@ exprTypmod(Node *expr)
break;
case T_NamedArgExpr:
return exprTypmod((Node *) ((NamedArgExpr *) expr)->arg);
+ case T_NullIfExpr:
+ {
+ /*
+ * Result is either first argument or NULL, so we can report
+ * first argument's typmod if known.
+ */
+ NullIfExpr *nexpr = (NullIfExpr *) expr;
+
+ return exprTypmod((Node *) linitial(nexpr->args));
+ }
+ break;
case T_SubLink:
{
SubLink *sublink = (SubLink *) expr;
@@ -444,13 +455,6 @@ exprTypmod(Node *expr)
return typmod;
}
break;
- case T_NullIfExpr:
- {
- NullIfExpr *nexpr = (NullIfExpr *) expr;
-
- return exprTypmod((Node *) linitial(nexpr->args));
- }
- break;
case T_CoerceToDomain:
return ((CoerceToDomain *) expr)->resulttypmod;
case T_CoerceToDomainValue:
@@ -466,8 +470,166 @@ exprTypmod(Node *expr)
}
/*
+ * exprIsLengthCoercion
+ * Detect whether an expression tree is an application of a datatype's
+ * typmod-coercion function. Optionally extract the result's typmod.
+ *
+ * If coercedTypmod is not NULL, the typmod is stored there if the expression
+ * is a length-coercion function, else -1 is stored there.
+ *
+ * Note that a combined type-and-length coercion will be treated as a
+ * length coercion by this routine.
+ */
+bool
+exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
+{
+ if (coercedTypmod != NULL)
+ *coercedTypmod = -1; /* default result on failure */
+
+ /*
+ * Scalar-type length coercions are FuncExprs, array-type length coercions
+ * are ArrayCoerceExprs
+ */
+ if (expr && IsA(expr, FuncExpr))
+ {
+ FuncExpr *func = (FuncExpr *) expr;
+ int nargs;
+ Const *second_arg;
+
+ /*
+ * If it didn't come from a coercion context, reject.
+ */
+ if (func->funcformat != COERCE_EXPLICIT_CAST &&
+ func->funcformat != COERCE_IMPLICIT_CAST)
+ return false;
+
+ /*
+ * If it's not a two-argument or three-argument function with the
+ * second argument being an int4 constant, it can't have been created
+ * from a length coercion (it must be a type coercion, instead).
+ */
+ nargs = list_length(func->args);
+ if (nargs < 2 || nargs > 3)
+ return false;
+
+ second_arg = (Const *) lsecond(func->args);
+ if (!IsA(second_arg, Const) ||
+ second_arg->consttype != INT4OID ||
+ second_arg->constisnull)
+ return false;
+
+ /*
+ * OK, it is indeed a length-coercion function.
+ */
+ if (coercedTypmod != NULL)
+ *coercedTypmod = DatumGetInt32(second_arg->constvalue);
+
+ return true;
+ }
+
+ if (expr && IsA(expr, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) expr;
+
+ /* It's not a length coercion unless there's a nondefault typmod */
+ if (acoerce->resulttypmod < 0)
+ return false;
+
+ /*
+ * OK, it is indeed a length-coercion expression.
+ */
+ if (coercedTypmod != NULL)
+ *coercedTypmod = acoerce->resulttypmod;
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * expression_returns_set
+ * Test whether an expression returns a set result.
+ *
+ * Because we use expression_tree_walker(), this can also be applied to
+ * whole targetlists; it'll produce TRUE if any one of the tlist items
+ * returns a set.
+ */
+bool
+expression_returns_set(Node *clause)
+{
+ return expression_returns_set_walker(clause, NULL);
+}
+
+static bool
+expression_returns_set_walker(Node *node, void *context)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, FuncExpr))
+ {
+ FuncExpr *expr = (FuncExpr *) node;
+
+ if (expr->funcretset)
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, OpExpr))
+ {
+ OpExpr *expr = (OpExpr *) node;
+
+ if (expr->opretset)
+ return true;
+ /* else fall through to check args */
+ }
+
+ /* Avoid recursion for some cases that can't return a set */
+ if (IsA(node, Aggref))
+ return false;
+ if (IsA(node, WindowFunc))
+ return false;
+ if (IsA(node, DistinctExpr))
+ return false;
+ if (IsA(node, NullIfExpr))
+ return false;
+ if (IsA(node, ScalarArrayOpExpr))
+ return false;
+ if (IsA(node, BoolExpr))
+ return false;
+ if (IsA(node, SubLink))
+ return false;
+ if (IsA(node, SubPlan))
+ return false;
+ if (IsA(node, AlternativeSubPlan))
+ return false;
+ if (IsA(node, ArrayExpr))
+ return false;
+ if (IsA(node, RowExpr))
+ return false;
+ if (IsA(node, RowCompareExpr))
+ return false;
+ if (IsA(node, CoalesceExpr))
+ return false;
+ if (IsA(node, MinMaxExpr))
+ return false;
+ if (IsA(node, XmlExpr))
+ return false;
+
+ return expression_tree_walker(node, expression_returns_set_walker,
+ context);
+}
+
+
+/*
* exprCollation -
* returns the Oid of the collation of the expression's result.
+ *
+ * Note: expression nodes that can invoke functions generally have an
+ * "inputcollid" field, which is what the function should use as collation.
+ * That is the resolved common collation of the node's inputs. It is often
+ * but not always the same as the result collation; in particular, if the
+ * function produces a non-collatable result type from collatable inputs
+ * or vice versa, the two are different.
*/
Oid
exprCollation(Node *expr)
@@ -486,34 +648,37 @@ exprCollation(Node *expr)
coll = ((Const *) expr)->constcollid;
break;
case T_Param:
- coll = ((Param *) expr)->paramcollation;
+ coll = ((Param *) expr)->paramcollid;
break;
case T_Aggref:
- coll = ((Aggref *) expr)->collid;
+ coll = ((Aggref *) expr)->aggcollid;
break;
case T_WindowFunc:
- coll = ((WindowFunc *) expr)->collid;
+ coll = ((WindowFunc *) expr)->wincollid;
break;
case T_ArrayRef:
coll = ((ArrayRef *) expr)->refcollid;
break;
case T_FuncExpr:
- coll = ((FuncExpr *) expr)->collid;
+ coll = ((FuncExpr *) expr)->funccollid;
break;
case T_NamedArgExpr:
coll = exprCollation((Node *) ((NamedArgExpr *) expr)->arg);
break;
case T_OpExpr:
- coll = ((OpExpr *) expr)->collid;
+ coll = ((OpExpr *) expr)->opcollid;
break;
case T_DistinctExpr:
- coll = ((DistinctExpr *) expr)->collid;
+ coll = ((DistinctExpr *) expr)->opcollid;
+ break;
+ case T_NullIfExpr:
+ coll = ((NullIfExpr *) expr)->opcollid;
break;
case T_ScalarArrayOpExpr:
- coll = ((ScalarArrayOpExpr *) expr)->collid;
+ coll = InvalidOid; /* result is always boolean */
break;
case T_BoolExpr:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always boolean */
break;
case T_SubLink:
{
@@ -522,7 +687,7 @@ exprCollation(Node *expr)
if (sublink->subLinkType == EXPR_SUBLINK ||
sublink->subLinkType == ARRAY_SUBLINK)
{
- /* get the collation of the subselect's first target column */
+ /* get the collation of subselect's first target column */
Query *qtree = (Query *) sublink->subselect;
TargetEntry *tent;
@@ -532,10 +697,13 @@ exprCollation(Node *expr)
Assert(IsA(tent, TargetEntry));
Assert(!tent->resjunk);
coll = exprCollation((Node *) tent->expr);
- /* note we don't need to care if it's an array */
+ /* collation doesn't change if it's converted to array */
}
else
+ {
+ /* for all other sublink types, result is boolean */
coll = InvalidOid;
+ }
}
break;
case T_SubPlan:
@@ -545,9 +713,9 @@ exprCollation(Node *expr)
if (subplan->subLinkType == EXPR_SUBLINK ||
subplan->subLinkType == ARRAY_SUBLINK)
{
- /* get the collation of the subselect's first target column */
- /* note we don't need to care if it's an array */
+ /* get the collation of subselect's first target column */
coll = subplan->firstColCollation;
+ /* collation doesn't change if it's converted to array */
}
else
{
@@ -565,84 +733,75 @@ exprCollation(Node *expr)
}
break;
case T_FieldSelect:
- coll = ((FieldSelect *) expr)->resultcollation;
+ coll = ((FieldSelect *) expr)->resultcollid;
break;
case T_FieldStore:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always composite */
break;
case T_RelabelType:
- coll = exprCollation((Node *) ((RelabelType *) expr)->arg);
+ coll = ((RelabelType *) expr)->resultcollid;
break;
case T_CoerceViaIO:
- {
- CoerceViaIO *cvio = (CoerceViaIO *) expr;
- coll = coercion_expression_result_collation(cvio->resulttype, (Node *) cvio->arg);
+ coll = ((CoerceViaIO *) expr)->resultcollid;
break;
- }
case T_ArrayCoerceExpr:
- {
- ArrayCoerceExpr *ace = (ArrayCoerceExpr *) expr;
- coll = coercion_expression_result_collation(ace->resulttype, (Node *) ace->arg);
+ coll = ((ArrayCoerceExpr *) expr)->resultcollid;
break;
- }
case T_ConvertRowtypeExpr:
- {
- ConvertRowtypeExpr *cre = (ConvertRowtypeExpr *) expr;
- coll = coercion_expression_result_collation(cre->resulttype, (Node *) cre->arg);
+ coll = InvalidOid; /* result is always composite */
break;
- }
case T_CollateExpr:
coll = ((CollateExpr *) expr)->collOid;
break;
case T_CaseExpr:
- coll = ((CaseExpr *) expr)->casecollation;
+ coll = ((CaseExpr *) expr)->casecollid;
break;
case T_CaseTestExpr:
coll = ((CaseTestExpr *) expr)->collation;
break;
case T_ArrayExpr:
- coll = get_typcollation(((ArrayExpr *) expr)->array_typeid);
+ coll = ((ArrayExpr *) expr)->array_collid;
break;
case T_RowExpr:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always composite */
break;
case T_RowCompareExpr:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always boolean */
break;
case T_CoalesceExpr:
- coll = ((CoalesceExpr *) expr)->coalescecollation;
+ coll = ((CoalesceExpr *) expr)->coalescecollid;
break;
case T_MinMaxExpr:
- coll = ((MinMaxExpr *) expr)->collid;
+ coll = ((MinMaxExpr *) expr)->minmaxcollid;
break;
case T_XmlExpr:
+ /*
+ * XMLSERIALIZE returns text from non-collatable inputs, so its
+ * collation is always default. The other cases return boolean
+ * or XML, which are non-collatable.
+ */
if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
coll = DEFAULT_COLLATION_OID;
else
coll = InvalidOid;
break;
- case T_NullIfExpr:
- coll = exprCollation((Node *) linitial(((NullIfExpr *) expr)->args));
- break;
case T_NullTest:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always boolean */
break;
case T_BooleanTest:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always boolean */
break;
case T_CoerceToDomain:
- coll = get_typcollation(((CoerceToDomain *) expr)->resulttype);
- if (coll == DEFAULT_COLLATION_OID)
- coll = exprCollation((Node *) ((CoerceToDomain *) expr)->arg);
+ coll = ((CoerceToDomain *) expr)->resultcollid;
break;
case T_CoerceToDomainValue:
- coll = get_typcollation(((CoerceToDomainValue *) expr)->typeId);
+ coll = ((CoerceToDomainValue *) expr)->collation;
break;
case T_SetToDefault:
- coll = ((SetToDefault *) expr)->collid;
+ coll = ((SetToDefault *) expr)->collation;
break;
case T_CurrentOfExpr:
- coll = InvalidOid; /* not applicable */
+ coll = InvalidOid; /* result is always boolean */
break;
case T_PlaceHolderVar:
coll = exprCollation((Node *) ((PlaceHolderVar *) expr)->phexpr);
@@ -652,176 +811,239 @@ exprCollation(Node *expr)
coll = InvalidOid; /* keep compiler quiet */
break;
}
-
return coll;
}
/*
- * Compute the result collation of a coercion-like expression that
- * converts arg to resulttype.
+ * exprInputCollation -
+ * returns the Oid of the collation a function should use, if available.
+ *
+ * Result is InvalidOid if the node type doesn't store this information.
*/
Oid
-coercion_expression_result_collation(Oid resulttype, Node *arg)
+exprInputCollation(Node *expr)
{
- if (type_is_collatable(resulttype))
+ Oid coll;
+
+ if (!expr)
+ return InvalidOid;
+
+ switch (nodeTag(expr))
{
- if (type_is_collatable(exprType(arg)))
- return exprCollation(arg);
- else
- return DEFAULT_COLLATION_OID;
+ case T_Aggref:
+ coll = ((Aggref *) expr)->inputcollid;
+ break;
+ case T_WindowFunc:
+ coll = ((WindowFunc *) expr)->inputcollid;
+ break;
+ case T_FuncExpr:
+ coll = ((FuncExpr *) expr)->inputcollid;
+ break;
+ case T_OpExpr:
+ coll = ((OpExpr *) expr)->inputcollid;
+ break;
+ case T_DistinctExpr:
+ coll = ((DistinctExpr *) expr)->inputcollid;
+ break;
+ case T_NullIfExpr:
+ coll = ((NullIfExpr *) expr)->inputcollid;
+ break;
+ case T_ScalarArrayOpExpr:
+ coll = ((ScalarArrayOpExpr *) expr)->inputcollid;
+ break;
+ case T_MinMaxExpr:
+ coll = ((MinMaxExpr *) expr)->inputcollid;
+ break;
+ default:
+ coll = InvalidOid;
+ break;
}
- else
- return InvalidOid;
+ return coll;
}
/*
- * exprIsLengthCoercion
- * Detect whether an expression tree is an application of a datatype's
- * typmod-coercion function. Optionally extract the result's typmod.
- *
- * If coercedTypmod is not NULL, the typmod is stored there if the expression
- * is a length-coercion function, else -1 is stored there.
+ * exprSetCollation -
+ * Assign collation information to an expression tree node.
*
- * Note that a combined type-and-length coercion will be treated as a
- * length coercion by this routine.
+ * Note: since this is only used during parse analysis, we don't need to
+ * worry about subplans or PlaceHolderVars.
*/
-bool
-exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
+void
+exprSetCollation(Node *expr, Oid collation)
{
- if (coercedTypmod != NULL)
- *coercedTypmod = -1; /* default result on failure */
-
- /*
- * Scalar-type length coercions are FuncExprs, array-type length coercions
- * are ArrayCoerceExprs
- */
- if (expr && IsA(expr, FuncExpr))
- {
- FuncExpr *func = (FuncExpr *) expr;
- int nargs;
- Const *second_arg;
-
- /*
- * If it didn't come from a coercion context, reject.
- */
- if (func->funcformat != COERCE_EXPLICIT_CAST &&
- func->funcformat != COERCE_IMPLICIT_CAST)
- return false;
-
- /*
- * If it's not a two-argument or three-argument function with the
- * second argument being an int4 constant, it can't have been created
- * from a length coercion (it must be a type coercion, instead).
- */
- nargs = list_length(func->args);
- if (nargs < 2 || nargs > 3)
- return false;
-
- second_arg = (Const *) lsecond(func->args);
- if (!IsA(second_arg, Const) ||
- second_arg->consttype != INT4OID ||
- second_arg->constisnull)
- return false;
-
- /*
- * OK, it is indeed a length-coercion function.
- */
- if (coercedTypmod != NULL)
- *coercedTypmod = DatumGetInt32(second_arg->constvalue);
-
- return true;
- }
-
- if (expr && IsA(expr, ArrayCoerceExpr))
+ switch (nodeTag(expr))
{
- ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) expr;
-
- /* It's not a length coercion unless there's a nondefault typmod */
- if (acoerce->resulttypmod < 0)
- return false;
+ case T_Var:
+ ((Var *) expr)->varcollid = collation;
+ break;
+ case T_Const:
+ ((Const *) expr)->constcollid = collation;
+ break;
+ case T_Param:
+ ((Param *) expr)->paramcollid = collation;
+ break;
+ case T_Aggref:
+ ((Aggref *) expr)->aggcollid = collation;
+ break;
+ case T_WindowFunc:
+ ((WindowFunc *) expr)->wincollid = collation;
+ break;
+ case T_ArrayRef:
+ ((ArrayRef *) expr)->refcollid = collation;
+ break;
+ case T_FuncExpr:
+ ((FuncExpr *) expr)->funccollid = collation;
+ break;
+ case T_NamedArgExpr:
+ Assert(collation == exprCollation((Node *) ((NamedArgExpr *) expr)->arg));
+ break;
+ case T_OpExpr:
+ ((OpExpr *) expr)->opcollid = collation;
+ break;
+ case T_DistinctExpr:
+ ((DistinctExpr *) expr)->opcollid = collation;
+ break;
+ case T_NullIfExpr:
+ ((NullIfExpr *) expr)->opcollid = collation;
+ break;
+ case T_ScalarArrayOpExpr:
+ Assert(!OidIsValid(collation)); /* result is always boolean */
+ break;
+ case T_BoolExpr:
+ Assert(!OidIsValid(collation)); /* result is always boolean */
+ break;
+ case T_SubLink:
+#ifdef USE_ASSERT_CHECKING
+ {
+ SubLink *sublink = (SubLink *) expr;
- /*
- * OK, it is indeed a length-coercion expression.
- */
- if (coercedTypmod != NULL)
- *coercedTypmod = acoerce->resulttypmod;
+ if (sublink->subLinkType == EXPR_SUBLINK ||
+ sublink->subLinkType == ARRAY_SUBLINK)
+ {
+ /* get the collation of subselect's first target column */
+ Query *qtree = (Query *) sublink->subselect;
+ TargetEntry *tent;
- return true;
+ if (!qtree || !IsA(qtree, Query))
+ elog(ERROR, "cannot set collation for untransformed sublink");
+ tent = (TargetEntry *) linitial(qtree->targetList);
+ Assert(IsA(tent, TargetEntry));
+ Assert(!tent->resjunk);
+ Assert(collation == exprCollation((Node *) tent->expr));
+ }
+ else
+ {
+ /* for all other sublink types, result is boolean */
+ Assert(!OidIsValid(collation));
+ }
+ }
+#endif /* USE_ASSERT_CHECKING */
+ break;
+ case T_FieldSelect:
+ ((FieldSelect *) expr)->resultcollid = collation;
+ break;
+ case T_FieldStore:
+ Assert(!OidIsValid(collation)); /* result is always composite */
+ break;
+ case T_RelabelType:
+ ((RelabelType *) expr)->resultcollid = collation;
+ break;
+ case T_CoerceViaIO:
+ ((CoerceViaIO *) expr)->resultcollid = collation;
+ break;
+ case T_ArrayCoerceExpr:
+ ((ArrayCoerceExpr *) expr)->resultcollid = collation;
+ break;
+ case T_ConvertRowtypeExpr:
+ Assert(!OidIsValid(collation)); /* result is always composite */
+ break;
+ case T_CaseExpr:
+ ((CaseExpr *) expr)->casecollid = collation;
+ break;
+ case T_ArrayExpr:
+ ((ArrayExpr *) expr)->array_collid = collation;
+ break;
+ case T_RowExpr:
+ Assert(!OidIsValid(collation)); /* result is always composite */
+ break;
+ case T_RowCompareExpr:
+ Assert(!OidIsValid(collation)); /* result is always boolean */
+ break;
+ case T_CoalesceExpr:
+ ((CoalesceExpr *) expr)->coalescecollid = collation;
+ break;
+ case T_MinMaxExpr:
+ ((MinMaxExpr *) expr)->minmaxcollid = collation;
+ break;
+ case T_XmlExpr:
+ Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
+ (collation == DEFAULT_COLLATION_OID) :
+ (collation == InvalidOid));
+ break;
+ case T_NullTest:
+ Assert(!OidIsValid(collation)); /* result is always boolean */
+ break;
+ case T_BooleanTest:
+ Assert(!OidIsValid(collation)); /* result is always boolean */
+ break;
+ case T_CoerceToDomain:
+ ((CoerceToDomain *) expr)->resultcollid = collation;
+ break;
+ case T_CoerceToDomainValue:
+ ((CoerceToDomainValue *) expr)->collation = collation;
+ break;
+ case T_SetToDefault:
+ ((SetToDefault *) expr)->collation = collation;
+ break;
+ case T_CurrentOfExpr:
+ Assert(!OidIsValid(collation)); /* result is always boolean */
+ break;
+ default:
+ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
+ break;
}
-
- return false;
}
/*
- * expression_returns_set
- * Test whether an expression returns a set result.
+ * exprSetInputCollation -
+ * Assign input-collation information to an expression tree node.
*
- * Because we use expression_tree_walker(), this can also be applied to
- * whole targetlists; it'll produce TRUE if any one of the tlist items
- * returns a set.
+ * This is a no-op for node types that don't store their input collation.
+ * Note we omit RowCompareExpr, which needs special treatment since it
+ * contains multiple input collation OIDs.
*/
-bool
-expression_returns_set(Node *clause)
+void
+exprSetInputCollation(Node *expr, Oid inputcollation)
{
- return expression_returns_set_walker(clause, NULL);
-}
-
-static bool
-expression_returns_set_walker(Node *node, void *context)
-{
- if (node == NULL)
- return false;
- if (IsA(node, FuncExpr))
- {
- FuncExpr *expr = (FuncExpr *) node;
-
- if (expr->funcretset)
- return true;
- /* else fall through to check args */
- }
- if (IsA(node, OpExpr))
+ switch (nodeTag(expr))
{
- OpExpr *expr = (OpExpr *) node;
-
- if (expr->opretset)
- return true;
- /* else fall through to check args */
+ case T_Aggref:
+ ((Aggref *) expr)->inputcollid = inputcollation;
+ break;
+ case T_WindowFunc:
+ ((WindowFunc *) expr)->inputcollid = inputcollation;
+ break;
+ case T_FuncExpr:
+ ((FuncExpr *) expr)->inputcollid = inputcollation;
+ break;
+ case T_OpExpr:
+ ((OpExpr *) expr)->inputcollid = inputcollation;
+ break;
+ case T_DistinctExpr:
+ ((DistinctExpr *) expr)->inputcollid = inputcollation;
+ break;
+ case T_NullIfExpr:
+ ((NullIfExpr *) expr)->inputcollid = inputcollation;
+ break;
+ case T_ScalarArrayOpExpr:
+ ((ScalarArrayOpExpr *) expr)->inputcollid = inputcollation;
+ break;
+ case T_MinMaxExpr:
+ ((MinMaxExpr *) expr)->inputcollid = inputcollation;
+ break;
+ default:
+ break;
}
-
- /* Avoid recursion for some cases that can't return a set */
- if (IsA(node, Aggref))
- return false;
- if (IsA(node, WindowFunc))
- return false;
- if (IsA(node, DistinctExpr))
- return false;
- if (IsA(node, ScalarArrayOpExpr))
- return false;
- if (IsA(node, BoolExpr))
- return false;
- if (IsA(node, SubLink))
- return false;
- if (IsA(node, SubPlan))
- return false;
- if (IsA(node, AlternativeSubPlan))
- return false;
- if (IsA(node, ArrayExpr))
- return false;
- if (IsA(node, RowExpr))
- return false;
- if (IsA(node, RowCompareExpr))
- return false;
- if (IsA(node, CoalesceExpr))
- return false;
- if (IsA(node, MinMaxExpr))
- return false;
- if (IsA(node, XmlExpr))
- return false;
- if (IsA(node, NullIfExpr))
- return false;
-
- return expression_tree_walker(node, expression_returns_set_walker,
- context);
}
@@ -1365,6 +1587,8 @@ expression_tree_walker(Node *node,
case T_NamedArgExpr:
return walker(((NamedArgExpr *) node)->arg, context);
case T_OpExpr:
+ case T_DistinctExpr: /* struct-equivalent to OpExpr */
+ case T_NullIfExpr: /* struct-equivalent to OpExpr */
{
OpExpr *expr = (OpExpr *) node;
@@ -1373,15 +1597,6 @@ expression_tree_walker(Node *node,
return true;
}
break;
- case T_DistinctExpr:
- {
- DistinctExpr *expr = (DistinctExpr *) node;
-
- if (expression_tree_walker((Node *) expr->args,
- walker, context))
- return true;
- }
- break;
case T_ScalarArrayOpExpr:
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
@@ -1502,8 +1717,6 @@ expression_tree_walker(Node *node,
return true;
}
break;
- case T_NullIfExpr:
- return walker(((NullIfExpr *) node)->args, context);
case T_NullTest:
return walker(((NullTest *) node)->arg, context);
case T_BooleanTest:
@@ -1648,8 +1861,11 @@ query_tree_walker(Query *query,
if (walker((Node *) query->cteList, context))
return true;
}
- if (range_table_walker(query->rtable, walker, context, flags))
- return true;
+ if (!(flags & QTW_IGNORE_RANGE_TABLE))
+ {
+ if (range_table_walker(query->rtable, walker, context, flags))
+ return true;
+ }
return false;
}
@@ -1908,6 +2124,16 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
+ case T_NullIfExpr:
+ {
+ NullIfExpr *expr = (NullIfExpr *) node;
+ NullIfExpr *newnode;
+
+ FLATCOPY(newnode, expr, NullIfExpr);
+ MUTATE(newnode->args, expr->args, List *);
+ return (Node *) newnode;
+ }
+ break;
case T_ScalarArrayOpExpr:
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
@@ -2127,16 +2353,6 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
- case T_NullIfExpr:
- {
- NullIfExpr *expr = (NullIfExpr *) node;
- NullIfExpr *newnode;
-
- FLATCOPY(newnode, expr, NullIfExpr);
- MUTATE(newnode->args, expr->args, List *);
- return (Node *) newnode;
- }
- break;
case T_NullTest:
{
NullTest *ntest = (NullTest *) node;