1515 *
1616 *
1717 * IDENTIFICATION
18- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.221 2007/01/22 20:00:40 tgl Exp $
18+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.222 2007/01/28 01:37:38 tgl Exp $
1919 *
2020 *-------------------------------------------------------------------------
2121 */
8888#include "optimizer/plancat.h"
8989#include "optimizer/restrictinfo.h"
9090#include "optimizer/var.h"
91+ #include "parser/parse_coerce.h"
9192#include "parser/parse_expr.h"
9293#include "parser/parsetree.h"
9394#include "utils/builtins.h"
9495#include "utils/date.h"
9596#include "utils/datum.h"
97+ #include "utils/fmgroids.h"
9698#include "utils/lsyscache.h"
9799#include "utils/nabstime.h"
98100#include "utils/pg_locale.h"
@@ -1448,6 +1450,63 @@ nulltestsel(PlannerInfo *root, NullTestType nulltesttype,
14481450return (Selectivity )selec ;
14491451}
14501452
1453+ /*
1454+ * strip_array_coercion - strip binary-compatible relabeling from an array expr
1455+ *
1456+ * For array values, the parser doesn't generate simple RelabelType nodes,
1457+ * but function calls of array_type_coerce() or array_type_length_coerce().
1458+ * If we want to cope with binary-compatible situations we have to look
1459+ * through these calls whenever the element-type coercion is binary-compatible.
1460+ */
1461+ static Node *
1462+ strip_array_coercion (Node * node )
1463+ {
1464+ /* could be more than one level, so loop */
1465+ for (;;)
1466+ {
1467+ if (node && IsA (node ,RelabelType ))
1468+ {
1469+ /* We don't really expect this case, but may as well cope */
1470+ node = (Node * ) ((RelabelType * )node )-> arg ;
1471+ }
1472+ else if (node && IsA (node ,FuncExpr ))
1473+ {
1474+ FuncExpr * fexpr = (FuncExpr * )node ;
1475+ Node * arg1 ;
1476+ Oid src_elem_type ;
1477+ Oid tgt_elem_type ;
1478+ Oid funcId ;
1479+
1480+ /* must be the right function(s) */
1481+ if (!(fexpr -> funcid == F_ARRAY_TYPE_COERCE ||
1482+ fexpr -> funcid == F_ARRAY_TYPE_LENGTH_COERCE ))
1483+ break ;
1484+
1485+ /* fetch source and destination array element types */
1486+ arg1 = (Node * )linitial (fexpr -> args );
1487+ src_elem_type = get_element_type (exprType (arg1 ));
1488+ if (src_elem_type == InvalidOid )
1489+ break ;/* probably shouldn't happen */
1490+ tgt_elem_type = get_element_type (fexpr -> funcresulttype );
1491+ if (tgt_elem_type == InvalidOid )
1492+ break ;/* probably shouldn't happen */
1493+
1494+ /* find out how to coerce */
1495+ if (!find_coercion_pathway (tgt_elem_type ,src_elem_type ,
1496+ COERCION_EXPLICIT ,& funcId ))
1497+ break ;/* definitely shouldn't happen */
1498+
1499+ if (OidIsValid (funcId ))
1500+ break ;/* non-binary-compatible coercion */
1501+
1502+ node = arg1 ;/* OK to look through the node */
1503+ }
1504+ else
1505+ break ;
1506+ }
1507+ return node ;
1508+ }
1509+
14511510/*
14521511 *scalararraysel- Selectivity of ScalarArrayOpExpr Node.
14531512 */
@@ -1461,6 +1520,7 @@ scalararraysel(PlannerInfo *root,
14611520bool useOr = clause -> useOr ;
14621521Node * leftop ;
14631522Node * rightop ;
1523+ Oid nominal_element_type ;
14641524RegProcedure oprsel ;
14651525FmgrInfo oprselproc ;
14661526Datum selarg4 ;
@@ -1484,6 +1544,19 @@ scalararraysel(PlannerInfo *root,
14841544return (Selectivity )0.5 ;
14851545fmgr_info (oprsel ,& oprselproc );
14861546
1547+ /* deconstruct the expression */
1548+ Assert (list_length (clause -> args )== 2 );
1549+ leftop = (Node * )linitial (clause -> args );
1550+ rightop = (Node * )lsecond (clause -> args );
1551+
1552+ /* get nominal (after relabeling) element type of rightop */
1553+ nominal_element_type = get_element_type (exprType (rightop ));
1554+ if (!OidIsValid (nominal_element_type ))
1555+ return (Selectivity )0.5 ;/* probably shouldn't happen */
1556+
1557+ /* look through any binary-compatible relabeling of rightop */
1558+ rightop = strip_array_coercion (rightop );
1559+
14871560/*
14881561 * We consider three cases:
14891562 *
@@ -1496,10 +1569,6 @@ scalararraysel(PlannerInfo *root,
14961569 *
14971570 * 3. otherwise, make a guess ...
14981571 */
1499- Assert (list_length (clause -> args )== 2 );
1500- leftop = (Node * )linitial (clause -> args );
1501- rightop = (Node * )lsecond (clause -> args );
1502-
15031572if (rightop && IsA (rightop ,Const ))
15041573{
15051574Datum arraydatum = ((Const * )rightop )-> constvalue ;
@@ -1529,7 +1598,7 @@ scalararraysel(PlannerInfo *root,
15291598Selectivity s2 ;
15301599
15311600args = list_make2 (leftop ,
1532- makeConst (ARR_ELEMTYPE ( arrayval ) ,
1601+ makeConst (nominal_element_type ,
15331602elmlen ,
15341603elem_values [i ],
15351604elem_nulls [i ],
@@ -1558,10 +1627,16 @@ scalararraysel(PlannerInfo *root,
15581627s1 = useOr ?0.0 :1.0 ;
15591628foreach (l ,arrayexpr -> elements )
15601629{
1630+ Node * elem = (Node * )lfirst (l );
15611631List * args ;
15621632Selectivity s2 ;
15631633
1564- args = list_make2 (leftop ,lfirst (l ));
1634+ /*
1635+ * Theoretically, if elem isn't of nominal_element_type we should
1636+ * insert a RelabelType, but it seems unlikely that any operator
1637+ * estimation function would really care ...
1638+ */
1639+ args = list_make2 (leftop ,elem );
15651640s2 = DatumGetFloat8 (FunctionCall4 (& oprselproc ,
15661641PointerGetDatum (root ),
15671642ObjectIdGetDatum (operator ),
@@ -1586,7 +1661,7 @@ scalararraysel(PlannerInfo *root,
15861661 * constant; CaseTestExpr is a convenient choice.
15871662 */
15881663dummyexpr = makeNode (CaseTestExpr );
1589- dummyexpr -> typeId = get_element_type ( exprType ( rightop )) ;
1664+ dummyexpr -> typeId = nominal_element_type ;
15901665dummyexpr -> typeMod = -1 ;
15911666args = list_make2 (leftop ,dummyexpr );
15921667s2 = DatumGetFloat8 (FunctionCall4 (& oprselproc ,