Re: [HACKERS] Allow use of stable functions with constraint exclusion

2007-05-08 Thread ITAGAKI Takahiro

Tom Lane <[EMAIL PROTECTED]> wrote:

> "Marshall, Steve" <[EMAIL PROTECTED]> writes:
> > I have developed a small patch to optimizer/util/plancat.c that 
> > eliminates one of hte caveats associated with constraint exclusions, 
> > namely the inability to avoid searching tables based on the results of 
> > stable functions.
> 
> Do you not understand why this is completely unsafe?

I think the proposal itself is very useful, because time-based
partitioning is commonly used and functions like now() or
CURRENT_TIMESTAMP are marked as stable.

I'm not clear why the optimization is unsafe. I'm confused to read the
definition of stable functions in our documentation. Which is required
for stable functions 'stable in a single table scan' or 'stable in a
SQL statements' ? If the latter definition is true, can we use them
in constraint exclusions?

| STABLE indicates that the function cannot modify the database, and
| that within a single table scan it will consistently return the same
| result for the same argument values, but that its result could change
| across SQL statements.

Regards,
---
ITAGAKI Takahiro
NTT Open Source Software Center



---(end of broadcast)---
TIP 4: Have you searched our list archives?

   http://archives.postgresql.org


Re: [HACKERS] Allow use of stable functions with constraint exclusion

2007-04-30 Thread Tom Lane
"Marshall, Steve" <[EMAIL PROTECTED]> writes:
> I have developed a small patch to optimizer/util/plancat.c that 
> eliminates one of hte caveats associated with constraint exclusions, 
> namely the inability to avoid searching tables based on the results of 
> stable functions.

Do you not understand why this is completely unsafe?

regards, tom lane

---(end of broadcast)---
TIP 2: Don't 'kill -9' the postmaster


[HACKERS] Allow use of stable functions with constraint exclusion

2007-04-30 Thread Marshall, Steve
I have developed a small patch to optimizer/util/plancat.c that 
eliminates one of hte caveats associated with constraint exclusions, 
namely the inability to avoid searching tables based on the results of 
stable functions.   The new code expands non-volatile functions into 
constant values so they can be used in the plan to determine which 
tables to search.  If volatile functions are used in the query 
constraints, they are correctly ignored in the planning process.


This is particularly useful for tables partitioned on a time column 
where queries relative to the current system time are desirable.


I'll attach the patch file and a small SQL test case that exercises the 
code.  The patch is relative to the 8.2.4 release; the SQL uses 
backslash commands, so its really only appropriate for use with the psql 
utility.  However, it does create a test database called test_ce_db and 
run all the tests with a single command, e.g. psql -f test_ce_patch.sql


I'd appreciate any feedback anyone has, particularly on any corner cases 
I may have missed.


Thanks,
Steve Marshall
*** plancat.c.orig  2007-04-30 12:17:55.785145396 -0400
--- plancat.c   2007-04-30 14:15:48.093639183 -0400
***
*** 473,478 
--- 473,479 
List   *constraint_pred;
List   *safe_constraints;
ListCell   *lc;
+   boolfound_unsafe_restrictions;
  
/* Skip the test if constraint exclusion is disabled */
if (!constraint_exclusion)
***
*** 486,491 
--- 487,493 
 * Note: strip off RestrictInfo because predicate_refuted_by() isn't
 * expecting to see any in its predicate argument.
 */
+   found_unsafe_restrictions = false;
safe_restrictions = NIL;
foreach(lc, rel->baserestrictinfo)
{
***
*** 493,498 
--- 495,502 
  
if (!contain_mutable_functions((Node *) rinfo->clause))
safe_restrictions = lappend(safe_restrictions, 
rinfo->clause);
+   else
+   found_unsafe_restrictions = true;
}
  
if (predicate_refuted_by(safe_restrictions, safe_restrictions))
***
*** 522,527 
--- 526,559 
}
  
/*
+*  Check the restrictions against the relation constraints.
+*  If we found mutable functions in the restrictions, try to simplify
+*  them prior to checking.  Effectively, this folds stable and 
immutable
+*  functions into constant values.  
+*/
+   if (found_unsafe_restrictions)
+   {
+   List * simp_restrictions = NIL;
+   foreach(lc, rel->baserestrictinfo)
+   {
+   RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+   Node * baseNode = (Node *) rinfo->clause;
+ 
+   if (IsA(baseNode, FuncExpr) || IsA(baseNode, OpExpr))
+   {
+   Node * simpNode = 
estimate_expression_value(baseNode);
+   simp_restrictions = lappend(simp_restrictions, 
simpNode);
+   }
+   else
+   {
+   simp_restrictions = lappend(simp_restrictions, 
baseNode);
+   }
+   }
+ 
+   if (predicate_refuted_by(safe_constraints, simp_restrictions))
+   return true;
+   }
+   /*
 * The constraints are effectively ANDed together, so we can just try to
 * refute the entire collection at once.  This may allow us to make 
proofs
 * that would fail if we took them individually.
***
*** 531,538 
 * have volatile and nonvolatile subclauses, and it's OK to make
 * deductions with the nonvolatile parts.
 */
!   if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo))
return true;
  
return false;
  }
--- 563,572 
 * have volatile and nonvolatile subclauses, and it's OK to make
 * deductions with the nonvolatile parts.
 */
!   else if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo))
!   {
return true;
+   }
  
return false;
  }
--
--  Create and connect to the test database
--
CREATE DATABASE test_ce_db;
ALTER DATABASE test_ce_db OWNER TO postgres;

\connect test_ce_db;

--
--  Make a parent table and three child tables partitioned by time using 
created_at column.
--
CREATE TABLE test_bulletins (
created_at timestamp with time zone NOT NULL,
data text NOT NULL
);

CREATE TABLE test_bulletins_20060908 (CONSTRAINT time_partition_limits CHECK 
(((created_at >= '2006-09-08 00:00:00+00'::timestamp with time zone) AND 
(created_at < '2006-09-09 00:00:00+00'::timestamp with time zone)))
)
INHERITS (test_bulletins);

CREATE TABLE test_bulletins_20060909 (CONSTRAINT