Hi Michael.

On 2017/11/30 9:07, Michael Paquier wrote:
> Hi all,
> 
> Since commit 4e5fe9ad (committer Robert Haas and author Amit Langote),
> coverity has been complaining that the new code of ExecFindPartition()
> may use a set of values and isnull values which never get initialized.
> This is a state which can be easily reached with the following SQLs of
> a parent partition with no children:
> create table parent_tab (a int) partition by list ((a+0));
> insert into parent_tab values (1);
> 
> The mistake is visibly that FormPartitionKeyDatum() should be called
> even for a root partition, initializing the fields of isnull and
> values on the way. That's actually what happens in execMain.c's
> ExecFindPartition() if you look at REL_10_STABLE. So the answer would
> be to move a bit down the quick exit code. Attached is a patch.
> 
> Amit, that's your code. What do you think?

Thanks for the report.  That's clearly a bug. :-(

Your patch seems enough to fix it.  I added a test and expanded the
comment a bit in the attached updated version.

Thanks,
Amit
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index d275cefe1d..8b334ea2ff 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -206,13 +206,6 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, 
PartitionDispatch *pd,
                        slot = myslot;
                }
 
-               /* Quick exit */
-               if (partdesc->nparts == 0)
-               {
-                       result = -1;
-                       break;
-               }
-
                /*
                 * Extract partition key from tuple. Expression evaluation 
machinery
                 * that FormPartitionKeyDatum() invokes expects ecxt_scantuple 
to
@@ -223,6 +216,17 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, 
PartitionDispatch *pd,
                 */
                ecxt->ecxt_scantuple = slot;
                FormPartitionKeyDatum(parent, slot, estate, values, isnull);
+
+               /*
+                * Nothing for get_partition_for_tuple() to do if there are no
+                * partitions to begin with.
+                */
+               if (partdesc->nparts == 0)
+               {
+                       result = -1;
+                       break;
+               }
+
                cur_index = get_partition_for_tuple(rel, values, isnull);
 
                /*
@@ -472,7 +476,7 @@ FormPartitionKeyDatum(PartitionDispatch pd,
 }
 
 /*
- * BuildSlotPartitionKeyDescription
+ * ExecBuildSlotPartitionKeyDescription
  *
  * This works very much like BuildIndexValueDescription() and is currently
  * used for building error messages when ExecFindPartition() fails to find
diff --git a/src/test/regress/expected/insert.out 
b/src/test/regress/expected/insert.out
index b7b37dbc39..dcbaad8e2f 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -165,6 +165,10 @@ create table range_parted (
        a text,
        b int
 ) partition by range (a, (b+0));
+-- no partitions, so fail
+insert into range_parted values ('a', 11);
+ERROR:  no partition of relation "range_parted" found for row
+DETAIL:  Partition key of the failing row contains (a, (b + 0)) = (a, 11).
 create table part1 partition of range_parted for values from ('a', 1) to ('a', 
10);
 create table part2 partition of range_parted for values from ('a', 10) to 
('a', 20);
 create table part3 partition of range_parted for values from ('b', 1) to ('b', 
10);
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index 310b818076..0150b6bb0f 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -90,6 +90,10 @@ create table range_parted (
        a text,
        b int
 ) partition by range (a, (b+0));
+
+-- no partitions, so fail
+insert into range_parted values ('a', 11);
+
 create table part1 partition of range_parted for values from ('a', 1) to ('a', 
10);
 create table part2 partition of range_parted for values from ('a', 10) to 
('a', 20);
 create table part3 partition of range_parted for values from ('b', 1) to ('b', 
10);

Reply via email to