aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/parse_coerce.c7
-rw-r--r--src/backend/parser/parse_expr.c39
2 files changed, 33 insertions, 13 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 24676404340..7933283cabc 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.161 2008/01/11 18:39:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.161.2.1 2008/10/25 17:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -961,7 +961,8 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
* 'typeids' is a nonempty list of type OIDs. Note that earlier items
* in the list will be preferred if there is doubt.
* 'context' is a phrase to use in the error message if we fail to select
- * a usable type.
+ * a usable type. Pass NULL to have the routine return InvalidOid
+ * rather than throwing an error on failure.
*/
Oid
select_common_type(List *typeids, const char *context)
@@ -1013,6 +1014,8 @@ select_common_type(List *typeids, const char *context)
/*
* both types in different categories? then not much hope...
*/
+ if (context == NULL)
+ return InvalidOid;
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index e174325c5e0..3f4f97e2bfe 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.226.2.1 2008/08/29 17:27:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.226.2.2 2008/10/25 17:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,6 +22,7 @@
#include "nodes/makefuncs.h"
#include "nodes/plannodes.h"
#include "optimizer/clauses.h"
+#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/gramparse.h"
#include "parser/parse_coerce.h"
@@ -887,25 +888,41 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
}
/*
- * If not forced by presence of RowExpr, try to resolve a common scalar
- * type for all the expressions, and see if it has an array type. (But if
- * there's only one righthand expression, we may as well just fall through
- * and generate a simple = comparison.)
+ * We prefer a boolean tree to ScalarArrayOpExpr if any of these are true:
+ *
+ * 1. We have a RowExpr anywhere.
+ *
+ * 2. There's only one righthand expression --- best to just generate a
+ * simple = comparison.
+ *
+ * 3. There's a reasonably small number of righthand expressions and
+ * they contain any Vars. This is a heuristic to support cases like
+ * WHERE '555-1212' IN (tab.home_phone, tab.work_phone), which can be
+ * optimized into an OR of indexscans on different indexes so long as
+ * it's left as an OR tree. (It'd be better to leave this decision
+ * to the planner, no doubt, but the amount of code required to reformat
+ * the expression later on seems out of proportion to the benefit.)
*/
- if (!haveRowExpr && list_length(rexprs) != 1)
+ if (!(haveRowExpr ||
+ list_length(rexprs) == 1 ||
+ (list_length(rexprs) <= 32 &&
+ contain_vars_of_level((Node *) rexprs, 0))))
{
Oid scalar_type;
Oid array_type;
/*
- * Select a common type for the array elements. Note that since the
- * LHS' type is first in the list, it will be preferred when there is
- * doubt (eg, when all the RHS items are unknown literals).
+ * Try to select a common type for the array elements. Note that
+ * since the LHS' type is first in the list, it will be preferred when
+ * there is doubt (eg, when all the RHS items are unknown literals).
*/
- scalar_type = select_common_type(typeids, "IN");
+ scalar_type = select_common_type(typeids, NULL);
/* Do we have an array type to use? */
- array_type = get_array_type(scalar_type);
+ if (OidIsValid(scalar_type))
+ array_type = get_array_type(scalar_type);
+ else
+ array_type = InvalidOid;
if (array_type != InvalidOid)
{
/*