8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.101 2002/06/20 20:29:31 momjian Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.102 2002/07/04 15:23:58 thomas Exp $
12
12
*
13
13
* HISTORY
14
14
* AUTHOR DATE MAJOR EVENT
@@ -71,6 +71,7 @@ make_clause(int type, Node *oper, List *args)
71
71
expr -> typeOid = BOOLOID ;
72
72
break ;
73
73
case OP_EXPR :
74
+ case DISTINCT_EXPR :
74
75
expr -> typeOid = ((Oper * ) oper )-> opresulttype ;
75
76
break ;
76
77
case FUNC_EXPR :
@@ -107,7 +108,8 @@ is_opclause(Node *clause)
107
108
{
108
109
return (clause != NULL &&
109
110
IsA (clause , Expr ) &&
110
- ((Expr * ) clause )-> opType == OP_EXPR );
111
+ ((((Expr * ) clause )-> opType == OP_EXPR ) ||
112
+ ((Expr * ) clause )-> opType == DISTINCT_EXPR ));
111
113
}
112
114
113
115
/*
@@ -458,7 +460,7 @@ pull_agg_clause_walker(Node *node, List **listptr)
458
460
459
461
/*
460
462
* expression_returns_set
461
- * Test whethe an expression returns a set result.
463
+ * Test whether an expression returns a set result.
462
464
*
463
465
* Because we use expression_tree_walker(), this can also be applied to
464
466
* whole targetlists; it'll produce TRUE if any one of the tlist items
@@ -482,6 +484,7 @@ expression_returns_set_walker(Node *node, void *context)
482
484
switch (expr -> opType )
483
485
{
484
486
case OP_EXPR :
487
+ case DISTINCT_EXPR :
485
488
if (((Oper * ) expr -> oper )-> opretset )
486
489
return true;
487
490
/* else fall through to check args */
@@ -757,6 +760,7 @@ contain_mutable_functions_walker(Node *node, void *context)
757
760
switch (expr -> opType )
758
761
{
759
762
case OP_EXPR :
763
+ case DISTINCT_EXPR :
760
764
if (op_volatile (((Oper * ) expr -> oper )-> opno ) != PROVOLATILE_IMMUTABLE )
761
765
return true;
762
766
break ;
@@ -806,6 +810,7 @@ contain_volatile_functions_walker(Node *node, void *context)
806
810
switch (expr -> opType )
807
811
{
808
812
case OP_EXPR :
813
+ case DISTINCT_EXPR :
809
814
if (op_volatile (((Oper * ) expr -> oper )-> opno ) == PROVOLATILE_VOLATILE )
810
815
return true;
811
816
break ;
@@ -1138,7 +1143,7 @@ eval_const_expressions_mutator(Node *node, void *context)
1138
1143
* expression_tree_mutator directly rather than recursing to self.
1139
1144
*/
1140
1145
args = (List * ) expression_tree_mutator ((Node * ) expr -> args ,
1141
- eval_const_expressions_mutator ,
1146
+ eval_const_expressions_mutator ,
1142
1147
(void * ) context );
1143
1148
1144
1149
switch (expr -> opType )
@@ -1159,6 +1164,97 @@ eval_const_expressions_mutator(Node *node, void *context)
1159
1164
* args
1160
1165
*/
1161
1166
break ;
1167
+ case DISTINCT_EXPR :
1168
+ {
1169
+ List * arg ;
1170
+ bool has_null_input = false;
1171
+ bool all_null_input = true;
1172
+ bool has_nonconst_input = false;
1173
+
1174
+ /*
1175
+ * Check for constant inputs and especially constant-NULL inputs.
1176
+ */
1177
+ Assert (length (args ) == 2 );
1178
+ foreach (arg , args )
1179
+ {
1180
+ if (IsA (lfirst (arg ), Const ))
1181
+ {
1182
+ has_null_input |= ((Const * ) lfirst (arg ))-> constisnull ;
1183
+ all_null_input &= ((Const * ) lfirst (arg ))-> constisnull ;
1184
+ }
1185
+ else
1186
+ {
1187
+ has_nonconst_input = true;
1188
+ }
1189
+ }
1190
+ /* all nulls? then not distinct */
1191
+ if (all_null_input )
1192
+ return MAKEBOOLCONST (false, false);
1193
+
1194
+ /* one null? then distinct */
1195
+ if (has_null_input )
1196
+ return MAKEBOOLCONST (true, false);
1197
+
1198
+ /* all constants? then optimize this out */
1199
+ if (!has_nonconst_input )
1200
+ {
1201
+ Oid result_typeid ;
1202
+ int16 resultTypLen ;
1203
+ bool resultTypByVal ;
1204
+ ExprContext * econtext ;
1205
+ Datum const_val ;
1206
+ bool const_is_null ;
1207
+
1208
+ Oper * oper = (Oper * ) expr -> oper ;
1209
+ replace_opid (oper ); /* OK to scribble on input to this extent */
1210
+ result_typeid = oper -> opresulttype ;
1211
+
1212
+ /*
1213
+ * OK, looks like we can simplify this operator/function.
1214
+ *
1215
+ * We use the executor's routine ExecEvalExpr() to avoid duplication of
1216
+ * code and ensure we get the same result as the executor would get.
1217
+ *
1218
+ * Build a new Expr node containing the already-simplified arguments. The
1219
+ * only other setup needed here is the replace_opid() that we already
1220
+ * did for the OP_EXPR case.
1221
+ */
1222
+ newexpr = makeNode (Expr );
1223
+ newexpr -> typeOid = expr -> typeOid ;
1224
+ newexpr -> opType = expr -> opType ;
1225
+ newexpr -> oper = expr -> oper ;
1226
+ newexpr -> args = args ;
1227
+
1228
+ /* Get info needed about result datatype */
1229
+ get_typlenbyval (result_typeid , & resultTypLen , & resultTypByVal );
1230
+
1231
+ /*
1232
+ * It is OK to pass a dummy econtext because none of the
1233
+ * ExecEvalExpr() code used in this situation will use econtext. That
1234
+ * might seem fortuitous, but it's not so unreasonable --- a constant
1235
+ * expression does not depend on context, by definition, n'est ce pas?
1236
+ */
1237
+ econtext = MakeExprContext (NULL , CurrentMemoryContext );
1238
+
1239
+ const_val = ExecEvalExprSwitchContext ((Node * ) newexpr , econtext ,
1240
+ & const_is_null , NULL );
1241
+
1242
+ /* Must copy result out of sub-context used by expression eval */
1243
+ if (!const_is_null )
1244
+ const_val = datumCopy (const_val , resultTypByVal , resultTypLen );
1245
+
1246
+ FreeExprContext (econtext );
1247
+ pfree (newexpr );
1248
+
1249
+ /*
1250
+ * Make the constant result node.
1251
+ */
1252
+ return (Node * ) makeConst (result_typeid , resultTypLen ,
1253
+ const_val , const_is_null ,
1254
+ resultTypByVal , false, false);
1255
+ }
1256
+ break ;
1257
+ }
1162
1258
case OR_EXPR :
1163
1259
{
1164
1260
0 commit comments