*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.221 2007/01/22 20:00:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.222 2007/01/28 01:37:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "optimizer/plancat.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/var.h"
+#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datum.h"
+#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/nabstime.h"
#include "utils/pg_locale.h"
return (Selectivity) selec;
}
+/*
+ * strip_array_coercion - strip binary-compatible relabeling from an array expr
+ *
+ * For array values, the parser doesn't generate simple RelabelType nodes,
+ * but function calls of array_type_coerce() or array_type_length_coerce().
+ * If we want to cope with binary-compatible situations we have to look
+ * through these calls whenever the element-type coercion is binary-compatible.
+ */
+static Node *
+strip_array_coercion(Node *node)
+{
+ /* could be more than one level, so loop */
+ for (;;)
+ {
+ if (node && IsA(node, RelabelType))
+ {
+ /* We don't really expect this case, but may as well cope */
+ node = (Node *) ((RelabelType *) node)->arg;
+ }
+ else if (node && IsA(node, FuncExpr))
+ {
+ FuncExpr *fexpr = (FuncExpr *) node;
+ Node *arg1;
+ Oid src_elem_type;
+ Oid tgt_elem_type;
+ Oid funcId;
+
+ /* must be the right function(s) */
+ if (!(fexpr->funcid == F_ARRAY_TYPE_COERCE ||
+ fexpr->funcid == F_ARRAY_TYPE_LENGTH_COERCE))
+ break;
+
+ /* fetch source and destination array element types */
+ arg1 = (Node *) linitial(fexpr->args);
+ src_elem_type = get_element_type(exprType(arg1));
+ if (src_elem_type == InvalidOid)
+ break; /* probably shouldn't happen */
+ tgt_elem_type = get_element_type(fexpr->funcresulttype);
+ if (tgt_elem_type == InvalidOid)
+ break; /* probably shouldn't happen */
+
+ /* find out how to coerce */
+ if (!find_coercion_pathway(tgt_elem_type, src_elem_type,
+ COERCION_EXPLICIT, &funcId))
+ break; /* definitely shouldn't happen */
+
+ if (OidIsValid(funcId))
+ break; /* non-binary-compatible coercion */
+
+ node = arg1; /* OK to look through the node */
+ }
+ else
+ break;
+ }
+ return node;
+}
+
/*
* scalararraysel - Selectivity of ScalarArrayOpExpr Node.
*/
bool useOr = clause->useOr;
Node *leftop;
Node *rightop;
+ Oid nominal_element_type;
RegProcedure oprsel;
FmgrInfo oprselproc;
Datum selarg4;
return (Selectivity) 0.5;
fmgr_info(oprsel, &oprselproc);
+ /* deconstruct the expression */
+ Assert(list_length(clause->args) == 2);
+ leftop = (Node *) linitial(clause->args);
+ rightop = (Node *) lsecond(clause->args);
+
+ /* get nominal (after relabeling) element type of rightop */
+ nominal_element_type = get_element_type(exprType(rightop));
+ if (!OidIsValid(nominal_element_type))
+ return (Selectivity) 0.5; /* probably shouldn't happen */
+
+ /* look through any binary-compatible relabeling of rightop */
+ rightop = strip_array_coercion(rightop);
+
/*
* We consider three cases:
*
*
* 3. otherwise, make a guess ...
*/
- Assert(list_length(clause->args) == 2);
- leftop = (Node *) linitial(clause->args);
- rightop = (Node *) lsecond(clause->args);
-
if (rightop && IsA(rightop, Const))
{
Datum arraydatum = ((Const *) rightop)->constvalue;
Selectivity s2;
args = list_make2(leftop,
- makeConst(ARR_ELEMTYPE(arrayval),
+ makeConst(nominal_element_type,
elmlen,
elem_values[i],
elem_nulls[i],
s1 = useOr ? 0.0 : 1.0;
foreach(l, arrayexpr->elements)
{
+ Node *elem = (Node *) lfirst(l);
List *args;
Selectivity s2;
- args = list_make2(leftop, lfirst(l));
+ /*
+ * Theoretically, if elem isn't of nominal_element_type we should
+ * insert a RelabelType, but it seems unlikely that any operator
+ * estimation function would really care ...
+ */
+ args = list_make2(leftop, elem);
s2 = DatumGetFloat8(FunctionCall4(&oprselproc,
PointerGetDatum(root),
ObjectIdGetDatum(operator),
* constant; CaseTestExpr is a convenient choice.
*/
dummyexpr = makeNode(CaseTestExpr);
- dummyexpr->typeId = get_element_type(exprType(rightop));
+ dummyexpr->typeId = nominal_element_type;
dummyexpr->typeMod = -1;
args = list_make2(leftop, dummyexpr);
s2 = DatumGetFloat8(FunctionCall4(&oprselproc,