Set ecxt_scantuple correctly for tuple routing.
authorRobert Haas <rhaas@postgresql.org>
Tue, 24 Jan 2017 20:34:39 +0000 (15:34 -0500)
committerRobert Haas <rhaas@postgresql.org>
Tue, 24 Jan 2017 20:34:39 +0000 (15:34 -0500)
In 2ac3ef7a01df859c62d0a02333b646d65eaec5ff, we changed things so that
it's possible for a different TupleTableSlot to be used for partitioned
tables at successively lower levels.  If we do end up changing the slot
from the original, we must update ecxt_scantuple to point to the new one
for partition key of the tuple to be computed correctly.

Reported by Rajkumar Raghuwanshi.  Patch by Amit Langote.

Discussion: http://postgr.es/m/CAKcux6%3Dm1qyqB2k6cjniuMMrYXb75O-MB4qGQMu8zg-iGGLjDw%40mail.gmail.com

src/backend/catalog/partition.c
src/backend/executor/execMain.c
src/test/regress/expected/insert.out
src/test/regress/sql/insert.sql

index e5af283997f8458dd8cc454805ea7efcfe458a2c..7be60529c5369d29b4bb0b5beaa4efd3886afdf7 100644 (file)
@@ -1679,7 +1679,10 @@ get_partition_for_tuple(PartitionDispatch *pd,
    bool        isnull[PARTITION_MAX_KEYS];
    int         cur_offset,
                cur_index;
-   int         i;
+   int         i,
+               result;
+   ExprContext *ecxt = GetPerTupleExprContext(estate);
+   TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
 
    /* start with the root partitioned table */
    parent = pd[0];
@@ -1708,7 +1711,15 @@ get_partition_for_tuple(PartitionDispatch *pd,
            slot = myslot;
        }
 
-       /* Extract partition key from tuple */
+       /*
+        * Extract partition key from tuple. Expression evaluation machinery
+        * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
+        * point to the correct tuple slot.  The slot might have changed from
+        * what was used for the parent table if the table of the current
+        * partitioning level has different tuple descriptor from the parent.
+        * So update ecxt_scantuple accordingly.
+        */
+       ecxt->ecxt_scantuple = slot;
        FormPartitionKeyDatum(parent, slot, estate, values, isnull);
 
        if (key->strategy == PARTITION_STRATEGY_RANGE)
@@ -1763,16 +1774,21 @@ get_partition_for_tuple(PartitionDispatch *pd,
         */
        if (cur_index < 0)
        {
+           result = -1;
            *failed_at = RelationGetRelid(parent->reldesc);
-           return -1;
+           break;
        }
-       else if (parent->indexes[cur_index] < 0)
-           parent = pd[-parent->indexes[cur_index]];
-       else
+       else if (parent->indexes[cur_index] >= 0)
+       {
+           result = parent->indexes[cur_index];
            break;
+       }
+       else
+           parent = pd[-parent->indexes[cur_index]];
    }
 
-   return parent->indexes[cur_index];
+   ecxt->ecxt_scantuple = ecxt_scantuple_old;
+   return result;
 }
 
 /*
index 4e8493ec141be0f83ae0e52255bc2b550d9a90a6..3a5b5b21265cf36db784c8741a3a200d6f8d0d1d 100644 (file)
@@ -3192,9 +3192,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
 {
    int         result;
    Oid         failed_at;
-   ExprContext *econtext = GetPerTupleExprContext(estate);
 
-   econtext->ecxt_scantuple = slot;
    result = get_partition_for_tuple(pd, slot, estate, &failed_at);
    if (result < 0)
    {
index 538fe5b1819e9b89a7bc6b0d5edb1dce14cb711d..81af3ef4972afa1a5ce0aa26135b3ce302817495 100644 (file)
@@ -320,7 +320,7 @@ drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg;
 drop table part_aa_bb, part_cc_dd, part_null, list_parted;
 -- more tests for certain multi-level partitioning scenarios
 create table p (a int, b int) partition by range (a, b);
-create table p1 (b int, a int not null) partition by range (b);
+create table p1 (b int not null, a int not null) partition by range ((b+0));
 create table p11 (like p1);
 alter table p11 drop a;
 alter table p11 add a int;
index 3d5138a8e0704ab98d180d78a171e8908fb248f5..454e1ce2e78a51ade614941025ddb8ef08b13f20 100644 (file)
@@ -193,7 +193,7 @@ drop table part_aa_bb, part_cc_dd, part_null, list_parted;
 
 -- more tests for certain multi-level partitioning scenarios
 create table p (a int, b int) partition by range (a, b);
-create table p1 (b int, a int not null) partition by range (b);
+create table p1 (b int not null, a int not null) partition by range ((b+0));
 create table p11 (like p1);
 alter table p11 drop a;
 alter table p11 add a int;