Thread

Commits

  1. Allow a partitioned table to have a default partition.

  2. Adjust min/max values when changing sequence type

  3. BRIN auto-summarization

  1. Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-03-01T00:59:28Z

    Hello,
    
    Currently inserting the data into a partitioned table that does not fit into
    any of its partitions is not allowed.
    
    The attached patch provides a capability to add a default partition to a
    list
    partitioned table as follows.
    
    postgres=# CREATE TABLE list_partitioned (
        a int
    ) PARTITION BY LIST (a);
    CREATE TABLE
    
    postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT);
    CREATE TABLE
    
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    (4,5);
    CREATE TABLE
    
    postgres=# insert into list_partitioned values (9);
    INSERT 0 1
    
    postgres=# select * from part_default;
     a
    ---
     9
    (1 row)
    
    The attached patch is in a  preliminary stage and has following ToDos:
    1. Adding pg_dump support.
    2. Documentation
    3. Handling adding a new partition to a partitioned table
       with default partition.
       This will require moving tuples from existing default partition to
      newly created partition if they satisfy its partition bound.
    4. Handling of update of partition key in a default partition. As per
    current design it should throw an error if the update requires the tuple to
    be moved to any other partition. But this can changed by the following
    proposal.
    
    https://www.postgresql.org/message-id/CAJ3gD9do9o2ccQ7j7+tSgiE1REY65XRiMb=
    yJO3u3QhyP8EEPQ@mail.gmail.com
    
    I am adding it to the current commitfest with the status Waiting on Author
    as I will submit an updated patch with above ToDos.
    Kindly give your suggestions.
    
    Thank you,
    Rahila Syed
    
  2. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-03-03T02:40:52Z

    On Wed, Mar 1, 2017 at 6:29 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    > 3. Handling adding a new partition to a partitioned table
    >    with default partition.
    >    This will require moving tuples from existing default partition to
    >   newly created partition if they satisfy its partition bound.
    
    Considering that this patch was submitted at the last minute and isn't
    even complete, I can't see this getting into v10.  But that doesn't
    mean we can't talk about it.  I'm curious to hear other opinions on
    whether we should have this feature.  On the point mentioned above, I
    don't think adding a partition should move tuples, necessarily; seems
    like it would be good enough - maybe better - for it to fail if there
    are any that would need to be moved.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  3. Re: Adding support for Default partition in partitioning

    David Fetter <david@fetter.org> — 2017-03-07T16:21:30Z

    On Fri, Mar 03, 2017 at 08:10:52AM +0530, Robert Haas wrote:
    > On Wed, Mar 1, 2017 at 6:29 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    > > 3. Handling adding a new partition to a partitioned table
    > >    with default partition.
    > >    This will require moving tuples from existing default partition to
    > >   newly created partition if they satisfy its partition bound.
    > 
    > Considering that this patch was submitted at the last minute and isn't
    > even complete, I can't see this getting into v10.  But that doesn't
    > mean we can't talk about it.  I'm curious to hear other opinions on
    > whether we should have this feature.  On the point mentioned above, I
    > don't think adding a partition should move tuples, necessarily; seems
    > like it would be good enough - maybe better - for it to fail if there
    > are any that would need to be moved.
    
    I see this as a bug fix.
    
    The current state of declarative partitions is such that you need way
    too much foresight in order to use them.  Missed adding a partition?
    Writes fail and can't be made to succeed.  This is not a failure mode
    we should be forcing on people, especially as it's a massive
    regression from the extant inheritance-based partitioning.
    
    Best,
    David.
    -- 
    David Fetter <david(at)fetter(dot)org> http://fetter.org/
    Phone: +1 415 235 3778  AIM: dfetter666  Yahoo!: dfetter
    Skype: davidfetter      XMPP: david(dot)fetter(at)gmail(dot)com
    
    Remember to vote!
    Consider donating to Postgres: http://www.postgresql.org/about/donate
    
    
    
  4. Re: Adding support for Default partition in partitioning

    Keith Fiske <keith@omniti.com> — 2017-03-07T16:30:59Z

    On Thu, Mar 2, 2017 at 9:40 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Wed, Mar 1, 2017 at 6:29 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > > 3. Handling adding a new partition to a partitioned table
    > >    with default partition.
    > >    This will require moving tuples from existing default partition to
    > >   newly created partition if they satisfy its partition bound.
    >
    > Considering that this patch was submitted at the last minute and isn't
    > even complete, I can't see this getting into v10.  But that doesn't
    > mean we can't talk about it.  I'm curious to hear other opinions on
    > whether we should have this feature.  On the point mentioned above, I
    > don't think adding a partition should move tuples, necessarily; seems
    > like it would be good enough - maybe better - for it to fail if there
    > are any that would need to be moved.
    >
    > --
    > Robert Haas
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    >
    > --
    > Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    > To make changes to your subscription:
    > http://www.postgresql.org/mailpref/pgsql-hackers
    >
    
    I'm all for this feature and had suggested it back in the original thread
    to add partitioning to 10. I agree that adding a new partition should not
    move any data out of the default. It's easy enough to set up a monitor to
    watch for data existing in the default. Perhaps also adding a column to
    pg_partitioned_table that contains the oid of the default partition so it's
    easier to identify from a system catalog perspective and make that
    monitoring easier. I don't even see a need for it to fail either and not
    quite sure how that would even work? If they can't add a necessary child
    due to data being in the default, how can they ever get it out? Just leave
    it to the user to keep an eye on the default and fix it as necessary. This
    is what I do in pg_partman.
    
    --
    Keith Fiske
    Database Administrator
    OmniTI Computer Consulting, Inc.
    http://www.keithf4.com
    
  5. Re: Adding support for Default partition in partitioning

    Jim Nasby <jim.nasby@openscg.com> — 2017-03-10T07:12:06Z

    On 3/7/17 10:30 AM, Keith Fiske wrote:
    > I'm all for this feature and had suggested it back in the original
    
    FWIW, I was working with a system just today that has an overflow partition.
    
    > thread to add partitioning to 10. I agree that adding a new partition
    > should not move any data out of the default. It's easy enough to set up
    
    +1
    
    > a monitor to watch for data existing in the default. Perhaps also adding
    > a column to pg_partitioned_table that contains the oid of the default
    > partition so it's easier to identify from a system catalog perspective
    > and make that monitoring easier. I don't even see a need for it to fail
    
    I agree that there should be a way to identify the default partition.
    
    > either and not quite sure how that would even work? If they can't add a
    > necessary child due to data being in the default, how can they ever get
    > it out?
    
    Yeah, was wondering that as well...
    -- 
    Jim Nasby, Chief Data Architect, OpenSCG
    http://OpenSCG.com
    
    
    
  6. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-03-10T13:04:44Z

     >I agree that adding a new partition should not move any data out of the
    default. It's easy enough to set up a monitor to watch for data existing in
    the >default. Perhaps also adding a column to pg_partitioned_table that
    contains the oid of the default partition so it's easier to identify from a
    system >catalog perspective and make that monitoring easier.
    
    Wont it incur overhead of scanning the default partition for matching rows
    each time a select happens on any matching partition?
    This extra scan would be required until rows satisfying the newly added
    partition are left around in default partition.
    
    >I don't even see a need for it to fail either and not quite sure how that
    would even work? If they can't add a necessary child due to data being in
    the >default, how can they ever get it out? Just leave it to the user to
    keep an eye on the default and fix it as necessary.
    This patch intends to provide a way to insert data that does not satisfy
    any of the existing partitions. For this patch, we can disallow adding a
    new partition when a default partition with conflicting rows exist. There
    can be many solutions to the problem of adding a new partition. One is to
    move the relevant tuples from default to the new partition or like you
    suggest keep monitoring the default partition until user moves the rows out
    of the default.
    
    Thank you,
    Rahila Syed
    
    On Tue, Mar 7, 2017 at 10:00 PM, Keith Fiske <keith@omniti.com> wrote:
    
    > On Thu, Mar 2, 2017 at 9:40 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    >
    >> On Wed, Mar 1, 2017 at 6:29 AM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >> > 3. Handling adding a new partition to a partitioned table
    >> >    with default partition.
    >> >    This will require moving tuples from existing default partition to
    >> >   newly created partition if they satisfy its partition bound.
    >>
    >> Considering that this patch was submitted at the last minute and isn't
    >> even complete, I can't see this getting into v10.  But that doesn't
    >> mean we can't talk about it.  I'm curious to hear other opinions on
    >> whether we should have this feature.  On the point mentioned above, I
    >> don't think adding a partition should move tuples, necessarily; seems
    >> like it would be good enough - maybe better - for it to fail if there
    >> are any that would need to be moved.
    >>
    >> --
    >> Robert Haas
    >> EnterpriseDB: http://www.enterprisedb.com
    >> The Enterprise PostgreSQL Company
    >>
    >>
    >> --
    >> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    >> To make changes to your subscription:
    >> http://www.postgresql.org/mailpref/pgsql-hackers
    >>
    >
    > I'm all for this feature and had suggested it back in the original thread
    > to add partitioning to 10. I agree that adding a new partition should not
    > move any data out of the default. It's easy enough to set up a monitor to
    > watch for data existing in the default. Perhaps also adding a column to
    > pg_partitioned_table that contains the oid of the default partition so it's
    > easier to identify from a system catalog perspective and make that
    > monitoring easier. I don't even see a need for it to fail either and not
    > quite sure how that would even work? If they can't add a necessary child
    > due to data being in the default, how can they ever get it out? Just leave
    > it to the user to keep an eye on the default and fix it as necessary. This
    > is what I do in pg_partman.
    >
    > --
    > Keith Fiske
    > Database Administrator
    > OmniTI Computer Consulting, Inc.
    > http://www.keithf4.com
    >
    
  7. Re: Adding support for Default partition in partitioning

    Peter Eisentraut <peter.eisentraut@2ndquadrant.com> — 2017-03-10T19:17:43Z

    On 3/2/17 21:40, Robert Haas wrote:
    > On the point mentioned above, I
    > don't think adding a partition should move tuples, necessarily; seems
    > like it would be good enough - maybe better - for it to fail if there
    > are any that would need to be moved.
    
    ISTM that the uses cases of various combinations of adding a default
    partition, adding another partition after it, removing the default
    partition, clearing out the default partition in order to add more
    nondefault partitions, and so on, need to be more clearly spelled out
    for each partitioning type.  We also need to consider that pg_dump and
    pg_upgrade need to be able to reproduce all those states.  Seems to be a
    bit of work still ...
    
    -- 
    Peter Eisentraut              http://www.2ndQuadrant.com/
    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
    
    
    
  8. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-03-13T00:12:05Z

    On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    <peter.eisentraut@2ndquadrant.com> wrote:
    > On 3/2/17 21:40, Robert Haas wrote:
    >> On the point mentioned above, I
    >> don't think adding a partition should move tuples, necessarily; seems
    >> like it would be good enough - maybe better - for it to fail if there
    >> are any that would need to be moved.
    >
    > ISTM that the uses cases of various combinations of adding a default
    > partition, adding another partition after it, removing the default
    > partition, clearing out the default partition in order to add more
    > nondefault partitions, and so on, need to be more clearly spelled out
    > for each partitioning type.  We also need to consider that pg_dump and
    > pg_upgrade need to be able to reproduce all those states.  Seems to be a
    > bit of work still ...
    
    This patch is only targeting list partitioning.   It is not entirely
    clear that the concept makes sense for range partitioning; you can
    already define a partition from the end of the last partitioning up to
    infinity, or from minus-infinity up to the starting point of the first
    partition.  The only thing a default range partition would do is let
    you do is have a single partition cover all of the ranges that would
    otherwise be unassigned, which might not even be something we want.
    
    I don't know how complete the patch is, but the specification seems
    clear enough.  If you have partitions for 1, 3, and 5, you get
    partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    default partition, you get a constraint of (a != 1 and a != 3 and a !=
    5).  If you then add a partition for 7, the default partition's
    constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    partition must be revalidated at that point for conflicting rows,
    which we can either try to move to the new partition, or just error
    out if there are any, depending on what we decide we want to do.  I
    don't think any of that requires any special handling for either
    pg_dump or pg_upgrade; it all just falls out of getting the
    partitioning constraints correct and consistently enforcing them, just
    as for any other partition.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  9. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-03-20T03:57:05Z

    Hello,
    
    Please find attached a rebased patch with support for pg_dump. I am working
    on the patch
    to handle adding a new partition after a default partition by throwing an
    error if
    conflicting rows exist in default partition and adding the partition
    successfully otherwise.
    Will post an updated patch by tomorrow.
    
    Thank you,
    Rahila Syed
    
    On Mon, Mar 13, 2017 at 5:42 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    > <peter.eisentraut@2ndquadrant.com> wrote:
    > > On 3/2/17 21:40, Robert Haas wrote:
    > >> On the point mentioned above, I
    > >> don't think adding a partition should move tuples, necessarily; seems
    > >> like it would be good enough - maybe better - for it to fail if there
    > >> are any that would need to be moved.
    > >
    > > ISTM that the uses cases of various combinations of adding a default
    > > partition, adding another partition after it, removing the default
    > > partition, clearing out the default partition in order to add more
    > > nondefault partitions, and so on, need to be more clearly spelled out
    > > for each partitioning type.  We also need to consider that pg_dump and
    > > pg_upgrade need to be able to reproduce all those states.  Seems to be a
    > > bit of work still ...
    >
    > This patch is only targeting list partitioning.   It is not entirely
    > clear that the concept makes sense for range partitioning; you can
    > already define a partition from the end of the last partitioning up to
    > infinity, or from minus-infinity up to the starting point of the first
    > partition.  The only thing a default range partition would do is let
    > you do is have a single partition cover all of the ranges that would
    > otherwise be unassigned, which might not even be something we want.
    >
    > I don't know how complete the patch is, but the specification seems
    > clear enough.  If you have partitions for 1, 3, and 5, you get
    > partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    > default partition, you get a constraint of (a != 1 and a != 3 and a !=
    > 5).  If you then add a partition for 7, the default partition's
    > constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    > partition must be revalidated at that point for conflicting rows,
    > which we can either try to move to the new partition, or just error
    > out if there are any, depending on what we decide we want to do.  I
    > don't think any of that requires any special handling for either
    > pg_dump or pg_upgrade; it all just falls out of getting the
    > partitioning constraints correct and consistently enforcing them, just
    > as for any other partition.
    >
    > --
    > Robert Haas
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  10. Re: Adding support for Default partition in partitioning

    Rushabh Lathia <rushabh.lathia@gmail.com> — 2017-03-21T06:06:00Z

    I picked this for review and noticed that patch is not getting
    cleanly complied on my environment.
    
    partition.c: In function ‘RelationBuildPartitionDesc’:
    partition.c:269:6: error: ISO C90 forbids mixed declarations and code
    [-Werror=declaration-after-statement]
          Const    *val = lfirst(c);
          ^
    partition.c: In function ‘generate_partition_qual’:
    partition.c:1590:2: error: ISO C90 forbids mixed declarations and code
    [-Werror=declaration-after-statement]
      PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
      ^
    partition.c: In function ‘get_partition_for_tuple’:
    partition.c:1820:5: error: array subscript has type ‘char’
    [-Werror=char-subscripts]
         result = parent->indexes[partdesc->boundinfo->def_index];
         ^
    partition.c:1824:16: error: assignment makes pointer from integer without a
    cast [-Werror]
         *failed_at = RelationGetRelid(parent->reldesc);
                    ^
    cc1: all warnings being treated as errors
    
    Apart from this, I was reading patch here are few more comments:
    
    1) Variable initializing happening at two place.
    
    @@ -166,6 +170,8 @@ RelationBuildPartitionDesc(Relation rel)
         /* List partitioning specific */
         PartitionListValue **all_values = NULL;
         bool        found_null = false;
    +    bool        found_def = false;
    +    int            def_index = -1;
         int            null_index = -1;
    
         /* Range partitioning specific */
    @@ -239,6 +245,8 @@ RelationBuildPartitionDesc(Relation rel)
                 i = 0;
                 found_null = false;
                 null_index = -1;
    +            found_def = false;
    +            def_index = -1;
                 foreach(cell, boundspecs)
                 {
                     ListCell   *c;
    @@ -249,6 +257,15 @@ RelationBuildPartitionDesc(Relation rel)
    
    
    2)
    
    @@ -1558,6 +1586,19 @@ generate_partition_qual(Relation rel)
         bound = stringToNode(TextDatumGetCString(boundDatum));
         ReleaseSysCache(tuple);
    
    +    /* Return if it is a default list partition */
    +    PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    +    ListCell *cell;
    +    foreach(cell, spec->listdatums)
    
    More comment on above hunk is needed?
    
    Rather then adding check for default here, I think this should be handle
    inside
    get_qual_for_list().
    
    3) Code is not aligned with existing
    
    diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
    index 6316688..ebb7db7 100644
    --- a/src/backend/parser/gram.y
    +++ b/src/backend/parser/gram.y
    @@ -2594,6 +2594,7 @@ partbound_datum:
                 Sconst            { $$ = makeStringConst($1, @1); }
                 | NumericOnly    { $$ = makeAConst($1, @1); }
                 | NULL_P        { $$ = makeNullAConst(@1); }
    +            | DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1); }
             ;
    
    
    4) Unnecessary hunk:
    
    @@ -2601,7 +2602,6 @@ partbound_datum_list:
                 | partbound_datum_list ',' partbound_datum
                                                     { $$ = lappend($1, $3); }
             ;
    -
    
    Note: this is just an initially review comments, I am yet to do the
    detailed review
    and the testing for the patch.
    
    Thanks.
    
    On Mon, Mar 20, 2017 at 9:27 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello,
    >
    > Please find attached a rebased patch with support for pg_dump. I am
    > working on the patch
    > to handle adding a new partition after a default partition by throwing an
    > error if
    > conflicting rows exist in default partition and adding the partition
    > successfully otherwise.
    > Will post an updated patch by tomorrow.
    >
    > Thank you,
    > Rahila Syed
    >
    > On Mon, Mar 13, 2017 at 5:42 AM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    >
    >> On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    >> <peter.eisentraut@2ndquadrant.com> wrote:
    >> > On 3/2/17 21:40, Robert Haas wrote:
    >> >> On the point mentioned above, I
    >> >> don't think adding a partition should move tuples, necessarily; seems
    >> >> like it would be good enough - maybe better - for it to fail if there
    >> >> are any that would need to be moved.
    >> >
    >> > ISTM that the uses cases of various combinations of adding a default
    >> > partition, adding another partition after it, removing the default
    >> > partition, clearing out the default partition in order to add more
    >> > nondefault partitions, and so on, need to be more clearly spelled out
    >> > for each partitioning type.  We also need to consider that pg_dump and
    >> > pg_upgrade need to be able to reproduce all those states.  Seems to be a
    >> > bit of work still ...
    >>
    >> This patch is only targeting list partitioning.   It is not entirely
    >> clear that the concept makes sense for range partitioning; you can
    >> already define a partition from the end of the last partitioning up to
    >> infinity, or from minus-infinity up to the starting point of the first
    >> partition.  The only thing a default range partition would do is let
    >> you do is have a single partition cover all of the ranges that would
    >> otherwise be unassigned, which might not even be something we want.
    >>
    >> I don't know how complete the patch is, but the specification seems
    >> clear enough.  If you have partitions for 1, 3, and 5, you get
    >> partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    >> default partition, you get a constraint of (a != 1 and a != 3 and a !=
    >> 5).  If you then add a partition for 7, the default partition's
    >> constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    >> partition must be revalidated at that point for conflicting rows,
    >> which we can either try to move to the new partition, or just error
    >> out if there are any, depending on what we decide we want to do.  I
    >> don't think any of that requires any special handling for either
    >> pg_dump or pg_upgrade; it all just falls out of getting the
    >> partitioning constraints correct and consistently enforcing them, just
    >> as for any other partition.
    >>
    >> --
    >> Robert Haas
    >> EnterpriseDB: http://www.enterprisedb.com
    >> The Enterprise PostgreSQL Company
    >>
    >
    >
    >
    > --
    > Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    > To make changes to your subscription:
    > http://www.postgresql.org/mailpref/pgsql-hackers
    >
    >
    
    
    -- 
    Rushabh Lathia
    
  11. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-03-24T09:55:02Z

    Hello Rushabh,
    
    Thank you for reviewing.
    Have addressed all your comments in the attached patch. The attached patch
    currently throws an
    error if a new partition is added after default partition.
    
    >Rather then adding check for default here, I think this should be handle
    inside
    >get_qual_for_list().
    Have moved the check inside get_qual_for_partbound() as needed to do some
    operations
    before calling get_qual_for_list() for default partitions.
    
    Thank you,
    Rahila Syed
    
    On Tue, Mar 21, 2017 at 11:36 AM, Rushabh Lathia <rushabh.lathia@gmail.com>
    wrote:
    
    > I picked this for review and noticed that patch is not getting
    > cleanly complied on my environment.
    >
    > partition.c: In function ‘RelationBuildPartitionDesc’:
    > partition.c:269:6: error: ISO C90 forbids mixed declarations and code
    > [-Werror=declaration-after-statement]
    >       Const    *val = lfirst(c);
    >       ^
    > partition.c: In function ‘generate_partition_qual’:
    > partition.c:1590:2: error: ISO C90 forbids mixed declarations and code
    > [-Werror=declaration-after-statement]
    >   PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >   ^
    > partition.c: In function ‘get_partition_for_tuple’:
    > partition.c:1820:5: error: array subscript has type ‘char’
    > [-Werror=char-subscripts]
    >      result = parent->indexes[partdesc->boundinfo->def_index];
    >      ^
    > partition.c:1824:16: error: assignment makes pointer from integer without
    > a cast [-Werror]
    >      *failed_at = RelationGetRelid(parent->reldesc);
    >                 ^
    > cc1: all warnings being treated as errors
    >
    > Apart from this, I was reading patch here are few more comments:
    >
    > 1) Variable initializing happening at two place.
    >
    > @@ -166,6 +170,8 @@ RelationBuildPartitionDesc(Relation rel)
    >      /* List partitioning specific */
    >      PartitionListValue **all_values = NULL;
    >      bool        found_null = false;
    > +    bool        found_def = false;
    > +    int            def_index = -1;
    >      int            null_index = -1;
    >
    >      /* Range partitioning specific */
    > @@ -239,6 +245,8 @@ RelationBuildPartitionDesc(Relation rel)
    >              i = 0;
    >              found_null = false;
    >              null_index = -1;
    > +            found_def = false;
    > +            def_index = -1;
    >              foreach(cell, boundspecs)
    >              {
    >                  ListCell   *c;
    > @@ -249,6 +257,15 @@ RelationBuildPartitionDesc(Relation rel)
    >
    >
    > 2)
    >
    > @@ -1558,6 +1586,19 @@ generate_partition_qual(Relation rel)
    >      bound = stringToNode(TextDatumGetCString(boundDatum));
    >      ReleaseSysCache(tuple);
    >
    > +    /* Return if it is a default list partition */
    > +    PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    > +    ListCell *cell;
    > +    foreach(cell, spec->listdatums)
    >
    > More comment on above hunk is needed?
    >
    > Rather then adding check for default here, I think this should be handle
    > inside
    > get_qual_for_list().
    >
    > 3) Code is not aligned with existing
    >
    > diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
    > index 6316688..ebb7db7 100644
    > --- a/src/backend/parser/gram.y
    > +++ b/src/backend/parser/gram.y
    > @@ -2594,6 +2594,7 @@ partbound_datum:
    >              Sconst            { $$ = makeStringConst($1, @1); }
    >              | NumericOnly    { $$ = makeAConst($1, @1); }
    >              | NULL_P        { $$ = makeNullAConst(@1); }
    > +            | DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1); }
    >          ;
    >
    >
    > 4) Unnecessary hunk:
    >
    > @@ -2601,7 +2602,6 @@ partbound_datum_list:
    >              | partbound_datum_list ',' partbound_datum
    >                                                  { $$ = lappend($1, $3); }
    >          ;
    > -
    >
    > Note: this is just an initially review comments, I am yet to do the
    > detailed review
    > and the testing for the patch.
    >
    > Thanks.
    >
    > On Mon, Mar 20, 2017 at 9:27 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    >
    >> Hello,
    >>
    >> Please find attached a rebased patch with support for pg_dump. I am
    >> working on the patch
    >> to handle adding a new partition after a default partition by throwing an
    >> error if
    >> conflicting rows exist in default partition and adding the partition
    >> successfully otherwise.
    >> Will post an updated patch by tomorrow.
    >>
    >> Thank you,
    >> Rahila Syed
    >>
    >> On Mon, Mar 13, 2017 at 5:42 AM, Robert Haas <robertmhaas@gmail.com>
    >> wrote:
    >>
    >>> On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    >>> <peter.eisentraut@2ndquadrant.com> wrote:
    >>> > On 3/2/17 21:40, Robert Haas wrote:
    >>> >> On the point mentioned above, I
    >>> >> don't think adding a partition should move tuples, necessarily; seems
    >>> >> like it would be good enough - maybe better - for it to fail if there
    >>> >> are any that would need to be moved.
    >>> >
    >>> > ISTM that the uses cases of various combinations of adding a default
    >>> > partition, adding another partition after it, removing the default
    >>> > partition, clearing out the default partition in order to add more
    >>> > nondefault partitions, and so on, need to be more clearly spelled out
    >>> > for each partitioning type.  We also need to consider that pg_dump and
    >>> > pg_upgrade need to be able to reproduce all those states.  Seems to be
    >>> a
    >>> > bit of work still ...
    >>>
    >>> This patch is only targeting list partitioning.   It is not entirely
    >>> clear that the concept makes sense for range partitioning; you can
    >>> already define a partition from the end of the last partitioning up to
    >>> infinity, or from minus-infinity up to the starting point of the first
    >>> partition.  The only thing a default range partition would do is let
    >>> you do is have a single partition cover all of the ranges that would
    >>> otherwise be unassigned, which might not even be something we want.
    >>>
    >>> I don't know how complete the patch is, but the specification seems
    >>> clear enough.  If you have partitions for 1, 3, and 5, you get
    >>> partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    >>> default partition, you get a constraint of (a != 1 and a != 3 and a !=
    >>> 5).  If you then add a partition for 7, the default partition's
    >>> constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    >>> partition must be revalidated at that point for conflicting rows,
    >>> which we can either try to move to the new partition, or just error
    >>> out if there are any, depending on what we decide we want to do.  I
    >>> don't think any of that requires any special handling for either
    >>> pg_dump or pg_upgrade; it all just falls out of getting the
    >>> partitioning constraints correct and consistently enforcing them, just
    >>> as for any other partition.
    >>>
    >>> --
    >>> Robert Haas
    >>> EnterpriseDB: http://www.enterprisedb.com
    >>> The Enterprise PostgreSQL Company
    >>>
    >>
    >>
    >>
    >> --
    >> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    >> To make changes to your subscription:
    >> http://www.postgresql.org/mailpref/pgsql-hackers
    >>
    >>
    >
    >
    > --
    > Rushabh Lathia
    >
    
  12. Re: Adding support for Default partition in partitioning

    Rushabh Lathia <rushabh.lathia@gmail.com> — 2017-03-27T06:40:23Z

    I applied the patch and was trying to perform some testing, but its
    ending up with server crash with the test shared by you in your starting
    mail:
    
    postgres=# CREATE TABLE list_partitioned (
    postgres(#     a int
    postgres(# ) PARTITION BY LIST (a);
    CREATE TABLE
    postgres=#
    postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT);
    CREATE TABLE
    
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    (4,5);
    server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
    The connection to the server was lost. Attempting reset: Failed.
    
    Apart from this, few more explanation in the patch is needed to explain the
    changes for the DEFAULT partition. Like I am not quite sure what exactly the
    latest version of patch supports, like does that support the tuple row
    movement,
    or adding new partition will be allowed having partition table having
    DEFAULT
    partition, which is quite difficult to understand through the code changes.
    
    Another part which is missing in the patch is the test coverage, adding
    proper test coverage, which explain what is supported and what's not.
    
    Thanks,
    
    On Fri, Mar 24, 2017 at 3:25 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello Rushabh,
    >
    > Thank you for reviewing.
    > Have addressed all your comments in the attached patch. The attached patch
    > currently throws an
    > error if a new partition is added after default partition.
    >
    > >Rather then adding check for default here, I think this should be handle
    > inside
    > >get_qual_for_list().
    > Have moved the check inside get_qual_for_partbound() as needed to do some
    > operations
    > before calling get_qual_for_list() for default partitions.
    >
    > Thank you,
    > Rahila Syed
    >
    > On Tue, Mar 21, 2017 at 11:36 AM, Rushabh Lathia <rushabh.lathia@gmail.com
    > > wrote:
    >
    >> I picked this for review and noticed that patch is not getting
    >> cleanly complied on my environment.
    >>
    >> partition.c: In function ‘RelationBuildPartitionDesc’:
    >> partition.c:269:6: error: ISO C90 forbids mixed declarations and code
    >> [-Werror=declaration-after-statement]
    >>       Const    *val = lfirst(c);
    >>       ^
    >> partition.c: In function ‘generate_partition_qual’:
    >> partition.c:1590:2: error: ISO C90 forbids mixed declarations and code
    >> [-Werror=declaration-after-statement]
    >>   PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >>   ^
    >> partition.c: In function ‘get_partition_for_tuple’:
    >> partition.c:1820:5: error: array subscript has type ‘char’
    >> [-Werror=char-subscripts]
    >>      result = parent->indexes[partdesc->boundinfo->def_index];
    >>      ^
    >> partition.c:1824:16: error: assignment makes pointer from integer without
    >> a cast [-Werror]
    >>      *failed_at = RelationGetRelid(parent->reldesc);
    >>                 ^
    >> cc1: all warnings being treated as errors
    >>
    >> Apart from this, I was reading patch here are few more comments:
    >>
    >> 1) Variable initializing happening at two place.
    >>
    >> @@ -166,6 +170,8 @@ RelationBuildPartitionDesc(Relation rel)
    >>      /* List partitioning specific */
    >>      PartitionListValue **all_values = NULL;
    >>      bool        found_null = false;
    >> +    bool        found_def = false;
    >> +    int            def_index = -1;
    >>      int            null_index = -1;
    >>
    >>      /* Range partitioning specific */
    >> @@ -239,6 +245,8 @@ RelationBuildPartitionDesc(Relation rel)
    >>              i = 0;
    >>              found_null = false;
    >>              null_index = -1;
    >> +            found_def = false;
    >> +            def_index = -1;
    >>              foreach(cell, boundspecs)
    >>              {
    >>                  ListCell   *c;
    >> @@ -249,6 +257,15 @@ RelationBuildPartitionDesc(Relation rel)
    >>
    >>
    >> 2)
    >>
    >> @@ -1558,6 +1586,19 @@ generate_partition_qual(Relation rel)
    >>      bound = stringToNode(TextDatumGetCString(boundDatum));
    >>      ReleaseSysCache(tuple);
    >>
    >> +    /* Return if it is a default list partition */
    >> +    PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >> +    ListCell *cell;
    >> +    foreach(cell, spec->listdatums)
    >>
    >> More comment on above hunk is needed?
    >>
    >> Rather then adding check for default here, I think this should be handle
    >> inside
    >> get_qual_for_list().
    >>
    >> 3) Code is not aligned with existing
    >>
    >> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
    >> index 6316688..ebb7db7 100644
    >> --- a/src/backend/parser/gram.y
    >> +++ b/src/backend/parser/gram.y
    >> @@ -2594,6 +2594,7 @@ partbound_datum:
    >>              Sconst            { $$ = makeStringConst($1, @1); }
    >>              | NumericOnly    { $$ = makeAConst($1, @1); }
    >>              | NULL_P        { $$ = makeNullAConst(@1); }
    >> +            | DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1); }
    >>          ;
    >>
    >>
    >> 4) Unnecessary hunk:
    >>
    >> @@ -2601,7 +2602,6 @@ partbound_datum_list:
    >>              | partbound_datum_list ',' partbound_datum
    >>                                                  { $$ = lappend($1, $3); }
    >>          ;
    >> -
    >>
    >> Note: this is just an initially review comments, I am yet to do the
    >> detailed review
    >> and the testing for the patch.
    >>
    >> Thanks.
    >>
    >> On Mon, Mar 20, 2017 at 9:27 AM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >>
    >>> Hello,
    >>>
    >>> Please find attached a rebased patch with support for pg_dump. I am
    >>> working on the patch
    >>> to handle adding a new partition after a default partition by throwing
    >>> an error if
    >>> conflicting rows exist in default partition and adding the partition
    >>> successfully otherwise.
    >>> Will post an updated patch by tomorrow.
    >>>
    >>> Thank you,
    >>> Rahila Syed
    >>>
    >>> On Mon, Mar 13, 2017 at 5:42 AM, Robert Haas <robertmhaas@gmail.com>
    >>> wrote:
    >>>
    >>>> On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    >>>> <peter.eisentraut@2ndquadrant.com> wrote:
    >>>> > On 3/2/17 21:40, Robert Haas wrote:
    >>>> >> On the point mentioned above, I
    >>>> >> don't think adding a partition should move tuples, necessarily; seems
    >>>> >> like it would be good enough - maybe better - for it to fail if there
    >>>> >> are any that would need to be moved.
    >>>> >
    >>>> > ISTM that the uses cases of various combinations of adding a default
    >>>> > partition, adding another partition after it, removing the default
    >>>> > partition, clearing out the default partition in order to add more
    >>>> > nondefault partitions, and so on, need to be more clearly spelled out
    >>>> > for each partitioning type.  We also need to consider that pg_dump and
    >>>> > pg_upgrade need to be able to reproduce all those states.  Seems to
    >>>> be a
    >>>> > bit of work still ...
    >>>>
    >>>> This patch is only targeting list partitioning.   It is not entirely
    >>>> clear that the concept makes sense for range partitioning; you can
    >>>> already define a partition from the end of the last partitioning up to
    >>>> infinity, or from minus-infinity up to the starting point of the first
    >>>> partition.  The only thing a default range partition would do is let
    >>>> you do is have a single partition cover all of the ranges that would
    >>>> otherwise be unassigned, which might not even be something we want.
    >>>>
    >>>> I don't know how complete the patch is, but the specification seems
    >>>> clear enough.  If you have partitions for 1, 3, and 5, you get
    >>>> partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    >>>> default partition, you get a constraint of (a != 1 and a != 3 and a !=
    >>>> 5).  If you then add a partition for 7, the default partition's
    >>>> constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    >>>> partition must be revalidated at that point for conflicting rows,
    >>>> which we can either try to move to the new partition, or just error
    >>>> out if there are any, depending on what we decide we want to do.  I
    >>>> don't think any of that requires any special handling for either
    >>>> pg_dump or pg_upgrade; it all just falls out of getting the
    >>>> partitioning constraints correct and consistently enforcing them, just
    >>>> as for any other partition.
    >>>>
    >>>> --
    >>>> Robert Haas
    >>>> EnterpriseDB: http://www.enterprisedb.com
    >>>> The Enterprise PostgreSQL Company
    >>>>
    >>>
    >>>
    >>>
    >>> --
    >>> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    >>> To make changes to your subscription:
    >>> http://www.postgresql.org/mailpref/pgsql-hackers
    >>>
    >>>
    >>
    >>
    >> --
    >> Rushabh Lathia
    >>
    >
    >
    
    
    -- 
    Rushabh Lathia
    
  13. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-03-27T11:06:01Z

    Hi Rahila,
    
    IIUC, your default_partition_v3.patch is trying to implement an error if new
    partition is added to a table already having a default partition.
    
    I too tried to run the test and similar to Rushabh, I see the server is
    crashing
    with the given test.
    
    However, if I reverse the order of creating the partitions, i.e. if I
    create a
    partition with list first and later create the default partition.
    
    The reason is, while defining new relation DefineRelation() checks for
    overlapping partitions by calling check_new_partition_bound(). Where in case
    of list partitions it assumes that the ndatums should be > 0, but in case of
    default partition that is 0.
    
    The crash here seems to be coming because, following assertion getting
    failed in
    function check_new_partition_bound():
    
    
    Assert(boundinfo &&
      boundinfo->strategy == PARTITION_STRATEGY_LIST &&
      (boundinfo->ndatums > 0 || boundinfo->has_null));
    
    
    So, I think the error you have added needs to be moved before this
    assertion:
    
    
    @@ -690,6 +715,12 @@ check_new_partition_bound(char *relname, Relation
    parent, Node *bound)
        boundinfo->strategy == PARTITION_STRATEGY_LIST &&
        (boundinfo->ndatums > 0 || boundinfo->has_null));
    
    + if (boundinfo->has_def)
    + ereport(ERROR,
    + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    + errmsg("parent table \"%s\" has a default partition",
    + RelationGetRelationName(parent))));
    
    
    If I do so, the server does not run into crash, and instead throws an error:
    
    postgres=# CREATE TABLE list_partitioned (
        a int
    ) PARTITION BY LIST (a);
    CREATE TABLE
    postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT);
    CREATE TABLE
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    (4,5);
    ERROR:  parent table "list_partitioned" has a default partition
    
    Regards,
    Jeevan Ladhe
    
    On Mon, Mar 27, 2017 at 12:10 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
    wrote:
    
    > I applied the patch and was trying to perform some testing, but its
    > ending up with server crash with the test shared by you in your starting
    > mail:
    >
    > postgres=# CREATE TABLE list_partitioned (
    > postgres(#     a int
    > postgres(# ) PARTITION BY LIST (a);
    > CREATE TABLE
    > postgres=#
    > postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    > VALUES IN (DEFAULT);
    > CREATE TABLE
    >
    > postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    > (4,5);
    > server closed the connection unexpectedly
    >     This probably means the server terminated abnormally
    >     before or while processing the request.
    > The connection to the server was lost. Attempting reset: Failed.
    >
    > Apart from this, few more explanation in the patch is needed to explain the
    > changes for the DEFAULT partition. Like I am not quite sure what exactly
    > the
    > latest version of patch supports, like does that support the tuple row
    > movement,
    > or adding new partition will be allowed having partition table having
    > DEFAULT
    > partition, which is quite difficult to understand through the code changes.
    >
    > Another part which is missing in the patch is the test coverage, adding
    > proper test coverage, which explain what is supported and what's not.
    >
    > Thanks,
    >
    > On Fri, Mar 24, 2017 at 3:25 PM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    >
    >> Hello Rushabh,
    >>
    >> Thank you for reviewing.
    >> Have addressed all your comments in the attached patch. The attached
    >> patch currently throws an
    >> error if a new partition is added after default partition.
    >>
    >> >Rather then adding check for default here, I think this should be
    >> handle inside
    >> >get_qual_for_list().
    >> Have moved the check inside get_qual_for_partbound() as needed to do some
    >> operations
    >> before calling get_qual_for_list() for default partitions.
    >>
    >> Thank you,
    >> Rahila Syed
    >>
    >> On Tue, Mar 21, 2017 at 11:36 AM, Rushabh Lathia <
    >> rushabh.lathia@gmail.com> wrote:
    >>
    >>> I picked this for review and noticed that patch is not getting
    >>> cleanly complied on my environment.
    >>>
    >>> partition.c: In function ‘RelationBuildPartitionDesc’:
    >>> partition.c:269:6: error: ISO C90 forbids mixed declarations and code
    >>> [-Werror=declaration-after-statement]
    >>>       Const    *val = lfirst(c);
    >>>       ^
    >>> partition.c: In function ‘generate_partition_qual’:
    >>> partition.c:1590:2: error: ISO C90 forbids mixed declarations and code
    >>> [-Werror=declaration-after-statement]
    >>>   PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >>>   ^
    >>> partition.c: In function ‘get_partition_for_tuple’:
    >>> partition.c:1820:5: error: array subscript has type ‘char’
    >>> [-Werror=char-subscripts]
    >>>      result = parent->indexes[partdesc->boundinfo->def_index];
    >>>      ^
    >>> partition.c:1824:16: error: assignment makes pointer from integer
    >>> without a cast [-Werror]
    >>>      *failed_at = RelationGetRelid(parent->reldesc);
    >>>                 ^
    >>> cc1: all warnings being treated as errors
    >>>
    >>> Apart from this, I was reading patch here are few more comments:
    >>>
    >>> 1) Variable initializing happening at two place.
    >>>
    >>> @@ -166,6 +170,8 @@ RelationBuildPartitionDesc(Relation rel)
    >>>      /* List partitioning specific */
    >>>      PartitionListValue **all_values = NULL;
    >>>      bool        found_null = false;
    >>> +    bool        found_def = false;
    >>> +    int            def_index = -1;
    >>>      int            null_index = -1;
    >>>
    >>>      /* Range partitioning specific */
    >>> @@ -239,6 +245,8 @@ RelationBuildPartitionDesc(Relation rel)
    >>>              i = 0;
    >>>              found_null = false;
    >>>              null_index = -1;
    >>> +            found_def = false;
    >>> +            def_index = -1;
    >>>              foreach(cell, boundspecs)
    >>>              {
    >>>                  ListCell   *c;
    >>> @@ -249,6 +257,15 @@ RelationBuildPartitionDesc(Relation rel)
    >>>
    >>>
    >>> 2)
    >>>
    >>> @@ -1558,6 +1586,19 @@ generate_partition_qual(Relation rel)
    >>>      bound = stringToNode(TextDatumGetCString(boundDatum));
    >>>      ReleaseSysCache(tuple);
    >>>
    >>> +    /* Return if it is a default list partition */
    >>> +    PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >>> +    ListCell *cell;
    >>> +    foreach(cell, spec->listdatums)
    >>>
    >>> More comment on above hunk is needed?
    >>>
    >>> Rather then adding check for default here, I think this should be handle
    >>> inside
    >>> get_qual_for_list().
    >>>
    >>> 3) Code is not aligned with existing
    >>>
    >>> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
    >>> index 6316688..ebb7db7 100644
    >>> --- a/src/backend/parser/gram.y
    >>> +++ b/src/backend/parser/gram.y
    >>> @@ -2594,6 +2594,7 @@ partbound_datum:
    >>>              Sconst            { $$ = makeStringConst($1, @1); }
    >>>              | NumericOnly    { $$ = makeAConst($1, @1); }
    >>>              | NULL_P        { $$ = makeNullAConst(@1); }
    >>> +            | DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1);
    >>> }
    >>>          ;
    >>>
    >>>
    >>> 4) Unnecessary hunk:
    >>>
    >>> @@ -2601,7 +2602,6 @@ partbound_datum_list:
    >>>              | partbound_datum_list ',' partbound_datum
    >>>                                                  { $$ = lappend($1, $3);
    >>> }
    >>>          ;
    >>> -
    >>>
    >>> Note: this is just an initially review comments, I am yet to do the
    >>> detailed review
    >>> and the testing for the patch.
    >>>
    >>> Thanks.
    >>>
    >>> On Mon, Mar 20, 2017 at 9:27 AM, Rahila Syed <rahilasyed90@gmail.com>
    >>> wrote:
    >>>
    >>>> Hello,
    >>>>
    >>>> Please find attached a rebased patch with support for pg_dump. I am
    >>>> working on the patch
    >>>> to handle adding a new partition after a default partition by throwing
    >>>> an error if
    >>>> conflicting rows exist in default partition and adding the partition
    >>>> successfully otherwise.
    >>>> Will post an updated patch by tomorrow.
    >>>>
    >>>> Thank you,
    >>>> Rahila Syed
    >>>>
    >>>> On Mon, Mar 13, 2017 at 5:42 AM, Robert Haas <robertmhaas@gmail.com>
    >>>> wrote:
    >>>>
    >>>>> On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    >>>>> <peter.eisentraut@2ndquadrant.com> wrote:
    >>>>> > On 3/2/17 21:40, Robert Haas wrote:
    >>>>> >> On the point mentioned above, I
    >>>>> >> don't think adding a partition should move tuples, necessarily;
    >>>>> seems
    >>>>> >> like it would be good enough - maybe better - for it to fail if
    >>>>> there
    >>>>> >> are any that would need to be moved.
    >>>>> >
    >>>>> > ISTM that the uses cases of various combinations of adding a default
    >>>>> > partition, adding another partition after it, removing the default
    >>>>> > partition, clearing out the default partition in order to add more
    >>>>> > nondefault partitions, and so on, need to be more clearly spelled out
    >>>>> > for each partitioning type.  We also need to consider that pg_dump
    >>>>> and
    >>>>> > pg_upgrade need to be able to reproduce all those states.  Seems to
    >>>>> be a
    >>>>> > bit of work still ...
    >>>>>
    >>>>> This patch is only targeting list partitioning.   It is not entirely
    >>>>> clear that the concept makes sense for range partitioning; you can
    >>>>> already define a partition from the end of the last partitioning up to
    >>>>> infinity, or from minus-infinity up to the starting point of the first
    >>>>> partition.  The only thing a default range partition would do is let
    >>>>> you do is have a single partition cover all of the ranges that would
    >>>>> otherwise be unassigned, which might not even be something we want.
    >>>>>
    >>>>> I don't know how complete the patch is, but the specification seems
    >>>>> clear enough.  If you have partitions for 1, 3, and 5, you get
    >>>>> partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    >>>>> default partition, you get a constraint of (a != 1 and a != 3 and a !=
    >>>>> 5).  If you then add a partition for 7, the default partition's
    >>>>> constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    >>>>> partition must be revalidated at that point for conflicting rows,
    >>>>> which we can either try to move to the new partition, or just error
    >>>>> out if there are any, depending on what we decide we want to do.  I
    >>>>> don't think any of that requires any special handling for either
    >>>>> pg_dump or pg_upgrade; it all just falls out of getting the
    >>>>> partitioning constraints correct and consistently enforcing them, just
    >>>>> as for any other partition.
    >>>>>
    >>>>> --
    >>>>> Robert Haas
    >>>>> EnterpriseDB: http://www.enterprisedb.com
    >>>>> The Enterprise PostgreSQL Company
    >>>>>
    >>>>
    >>>>
    >>>>
    >>>> --
    >>>> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    >>>> To make changes to your subscription:
    >>>> http://www.postgresql.org/mailpref/pgsql-hackers
    >>>>
    >>>>
    >>>
    >>>
    >>> --
    >>> Rushabh Lathia
    >>>
    >>
    >>
    >
    >
    > --
    > Rushabh Lathia
    >
    
  14. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-03-29T12:13:59Z

    Thanks for reporting. I have identified the problem and have a fix.
    Currently working on allowing
    adding a partition after default partition if the default partition does
    not have any conflicting rows.
    Will update the patch with both of these.
    
    Thank you,
    Rahila Syed
    
    On Mon, Mar 27, 2017 at 12:10 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
    wrote:
    
    > I applied the patch and was trying to perform some testing, but its
    > ending up with server crash with the test shared by you in your starting
    > mail:
    >
    > postgres=# CREATE TABLE list_partitioned (
    > postgres(#     a int
    > postgres(# ) PARTITION BY LIST (a);
    > CREATE TABLE
    > postgres=#
    > postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    > VALUES IN (DEFAULT);
    > CREATE TABLE
    >
    > postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    > (4,5);
    > server closed the connection unexpectedly
    >     This probably means the server terminated abnormally
    >     before or while processing the request.
    > The connection to the server was lost. Attempting reset: Failed.
    >
    > Apart from this, few more explanation in the patch is needed to explain the
    > changes for the DEFAULT partition. Like I am not quite sure what exactly
    > the
    > latest version of patch supports, like does that support the tuple row
    > movement,
    > or adding new partition will be allowed having partition table having
    > DEFAULT
    > partition, which is quite difficult to understand through the code changes.
    >
    > Another part which is missing in the patch is the test coverage, adding
    > proper test coverage, which explain what is supported and what's not.
    >
    > Thanks,
    >
    > On Fri, Mar 24, 2017 at 3:25 PM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    >
    >> Hello Rushabh,
    >>
    >> Thank you for reviewing.
    >> Have addressed all your comments in the attached patch. The attached
    >> patch currently throws an
    >> error if a new partition is added after default partition.
    >>
    >> >Rather then adding check for default here, I think this should be
    >> handle inside
    >> >get_qual_for_list().
    >> Have moved the check inside get_qual_for_partbound() as needed to do some
    >> operations
    >> before calling get_qual_for_list() for default partitions.
    >>
    >> Thank you,
    >> Rahila Syed
    >>
    >> On Tue, Mar 21, 2017 at 11:36 AM, Rushabh Lathia <
    >> rushabh.lathia@gmail.com> wrote:
    >>
    >>> I picked this for review and noticed that patch is not getting
    >>> cleanly complied on my environment.
    >>>
    >>> partition.c: In function ‘RelationBuildPartitionDesc’:
    >>> partition.c:269:6: error: ISO C90 forbids mixed declarations and code
    >>> [-Werror=declaration-after-statement]
    >>>       Const    *val = lfirst(c);
    >>>       ^
    >>> partition.c: In function ‘generate_partition_qual’:
    >>> partition.c:1590:2: error: ISO C90 forbids mixed declarations and code
    >>> [-Werror=declaration-after-statement]
    >>>   PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >>>   ^
    >>> partition.c: In function ‘get_partition_for_tuple’:
    >>> partition.c:1820:5: error: array subscript has type ‘char’
    >>> [-Werror=char-subscripts]
    >>>      result = parent->indexes[partdesc->boundinfo->def_index];
    >>>      ^
    >>> partition.c:1824:16: error: assignment makes pointer from integer
    >>> without a cast [-Werror]
    >>>      *failed_at = RelationGetRelid(parent->reldesc);
    >>>                 ^
    >>> cc1: all warnings being treated as errors
    >>>
    >>> Apart from this, I was reading patch here are few more comments:
    >>>
    >>> 1) Variable initializing happening at two place.
    >>>
    >>> @@ -166,6 +170,8 @@ RelationBuildPartitionDesc(Relation rel)
    >>>      /* List partitioning specific */
    >>>      PartitionListValue **all_values = NULL;
    >>>      bool        found_null = false;
    >>> +    bool        found_def = false;
    >>> +    int            def_index = -1;
    >>>      int            null_index = -1;
    >>>
    >>>      /* Range partitioning specific */
    >>> @@ -239,6 +245,8 @@ RelationBuildPartitionDesc(Relation rel)
    >>>              i = 0;
    >>>              found_null = false;
    >>>              null_index = -1;
    >>> +            found_def = false;
    >>> +            def_index = -1;
    >>>              foreach(cell, boundspecs)
    >>>              {
    >>>                  ListCell   *c;
    >>> @@ -249,6 +257,15 @@ RelationBuildPartitionDesc(Relation rel)
    >>>
    >>>
    >>> 2)
    >>>
    >>> @@ -1558,6 +1586,19 @@ generate_partition_qual(Relation rel)
    >>>      bound = stringToNode(TextDatumGetCString(boundDatum));
    >>>      ReleaseSysCache(tuple);
    >>>
    >>> +    /* Return if it is a default list partition */
    >>> +    PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
    >>> +    ListCell *cell;
    >>> +    foreach(cell, spec->listdatums)
    >>>
    >>> More comment on above hunk is needed?
    >>>
    >>> Rather then adding check for default here, I think this should be handle
    >>> inside
    >>> get_qual_for_list().
    >>>
    >>> 3) Code is not aligned with existing
    >>>
    >>> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
    >>> index 6316688..ebb7db7 100644
    >>> --- a/src/backend/parser/gram.y
    >>> +++ b/src/backend/parser/gram.y
    >>> @@ -2594,6 +2594,7 @@ partbound_datum:
    >>>              Sconst            { $$ = makeStringConst($1, @1); }
    >>>              | NumericOnly    { $$ = makeAConst($1, @1); }
    >>>              | NULL_P        { $$ = makeNullAConst(@1); }
    >>> +            | DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1);
    >>> }
    >>>          ;
    >>>
    >>>
    >>> 4) Unnecessary hunk:
    >>>
    >>> @@ -2601,7 +2602,6 @@ partbound_datum_list:
    >>>              | partbound_datum_list ',' partbound_datum
    >>>                                                  { $$ = lappend($1, $3);
    >>> }
    >>>          ;
    >>> -
    >>>
    >>> Note: this is just an initially review comments, I am yet to do the
    >>> detailed review
    >>> and the testing for the patch.
    >>>
    >>> Thanks.
    >>>
    >>> On Mon, Mar 20, 2017 at 9:27 AM, Rahila Syed <rahilasyed90@gmail.com>
    >>> wrote:
    >>>
    >>>> Hello,
    >>>>
    >>>> Please find attached a rebased patch with support for pg_dump. I am
    >>>> working on the patch
    >>>> to handle adding a new partition after a default partition by throwing
    >>>> an error if
    >>>> conflicting rows exist in default partition and adding the partition
    >>>> successfully otherwise.
    >>>> Will post an updated patch by tomorrow.
    >>>>
    >>>> Thank you,
    >>>> Rahila Syed
    >>>>
    >>>> On Mon, Mar 13, 2017 at 5:42 AM, Robert Haas <robertmhaas@gmail.com>
    >>>> wrote:
    >>>>
    >>>>> On Fri, Mar 10, 2017 at 2:17 PM, Peter Eisentraut
    >>>>> <peter.eisentraut@2ndquadrant.com> wrote:
    >>>>> > On 3/2/17 21:40, Robert Haas wrote:
    >>>>> >> On the point mentioned above, I
    >>>>> >> don't think adding a partition should move tuples, necessarily;
    >>>>> seems
    >>>>> >> like it would be good enough - maybe better - for it to fail if
    >>>>> there
    >>>>> >> are any that would need to be moved.
    >>>>> >
    >>>>> > ISTM that the uses cases of various combinations of adding a default
    >>>>> > partition, adding another partition after it, removing the default
    >>>>> > partition, clearing out the default partition in order to add more
    >>>>> > nondefault partitions, and so on, need to be more clearly spelled out
    >>>>> > for each partitioning type.  We also need to consider that pg_dump
    >>>>> and
    >>>>> > pg_upgrade need to be able to reproduce all those states.  Seems to
    >>>>> be a
    >>>>> > bit of work still ...
    >>>>>
    >>>>> This patch is only targeting list partitioning.   It is not entirely
    >>>>> clear that the concept makes sense for range partitioning; you can
    >>>>> already define a partition from the end of the last partitioning up to
    >>>>> infinity, or from minus-infinity up to the starting point of the first
    >>>>> partition.  The only thing a default range partition would do is let
    >>>>> you do is have a single partition cover all of the ranges that would
    >>>>> otherwise be unassigned, which might not even be something we want.
    >>>>>
    >>>>> I don't know how complete the patch is, but the specification seems
    >>>>> clear enough.  If you have partitions for 1, 3, and 5, you get
    >>>>> partition constraints of (a = 1), (a = 3), and (a = 5).  If you add a
    >>>>> default partition, you get a constraint of (a != 1 and a != 3 and a !=
    >>>>> 5).  If you then add a partition for 7, the default partition's
    >>>>> constraint becomes (a != 1 and a != 3 and a != 5 and a != 7).  The
    >>>>> partition must be revalidated at that point for conflicting rows,
    >>>>> which we can either try to move to the new partition, or just error
    >>>>> out if there are any, depending on what we decide we want to do.  I
    >>>>> don't think any of that requires any special handling for either
    >>>>> pg_dump or pg_upgrade; it all just falls out of getting the
    >>>>> partitioning constraints correct and consistently enforcing them, just
    >>>>> as for any other partition.
    >>>>>
    >>>>> --
    >>>>> Robert Haas
    >>>>> EnterpriseDB: http://www.enterprisedb.com
    >>>>> The Enterprise PostgreSQL Company
    >>>>>
    >>>>
    >>>>
    >>>>
    >>>> --
    >>>> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    >>>> To make changes to your subscription:
    >>>> http://www.postgresql.org/mailpref/pgsql-hackers
    >>>>
    >>>>
    >>>
    >>>
    >>> --
    >>> Rushabh Lathia
    >>>
    >>
    >>
    >
    >
    > --
    > Rushabh Lathia
    >
    
  15. Re: Adding support for Default partition in partitioning

    David Steele <david@pgmasters.net> — 2017-03-31T14:45:36Z

    On 3/29/17 8:13 AM, Rahila Syed wrote:
    
    > Thanks for reporting. I have identified the problem and have a fix.
    > Currently working on allowing
    > adding a partition after default partition if the default partition does
    > not have any conflicting rows.
    > Will update the patch with both of these.
    
    The CF has been extended but until April 7 but time is still growing 
    short.  Please respond with a new patch by 2017-04-04 00:00 AoE (UTC-12) 
    or this submission will be marked "Returned with Feedback".
    
    Thanks,
    -- 
    -David
    david@pgmasters.net
    
    
    
  16. Re: Adding support for Default partition in partitioning

    David Steele <david@pgmasters.net> — 2017-04-04T12:52:00Z

    On 3/31/17 10:45 AM, David Steele wrote:
    > On 3/29/17 8:13 AM, Rahila Syed wrote:
    > 
    >> Thanks for reporting. I have identified the problem and have a fix.
    >> Currently working on allowing
    >> adding a partition after default partition if the default partition does
    >> not have any conflicting rows.
    >> Will update the patch with both of these.
    > 
    > The CF has been extended but until April 7 but time is still growing
    > short.  Please respond with a new patch by 2017-04-04 00:00 AoE (UTC-12)
    > or this submission will be marked "Returned with Feedback".
    
    This submission has been marked "Returned with Feedback".  Please feel
    free to resubmit to a future commitfest.
    
    Regards,
    -- 
    -David
    david@pgmasters.net
    
    
    
  17. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-04T13:30:21Z

    Hello,
    
    Please find attached an updated patch.
    Following has been accomplished in this update:
    
    1. A new partition can be added after default partition if there are no
    conflicting rows in default partition.
    2. Solved the crash reported earlier.
    
    Thank you,
    Rahila Syed
    
    
    
    On Tue, Apr 4, 2017 at 6:22 PM, David Steele <david@pgmasters.net> wrote:
    
    > On 3/31/17 10:45 AM, David Steele wrote:
    > > On 3/29/17 8:13 AM, Rahila Syed wrote:
    > >
    > >> Thanks for reporting. I have identified the problem and have a fix.
    > >> Currently working on allowing
    > >> adding a partition after default partition if the default partition does
    > >> not have any conflicting rows.
    > >> Will update the patch with both of these.
    > >
    > > The CF has been extended but until April 7 but time is still growing
    > > short.  Please respond with a new patch by 2017-04-04 00:00 AoE (UTC-12)
    > > or this submission will be marked "Returned with Feedback".
    >
    > This submission has been marked "Returned with Feedback".  Please feel
    > free to resubmit to a future commitfest.
    >
    > Regards,
    > --
    > -David
    > david@pgmasters.net
    >
    
  18. Re: Adding support for Default partition in partitioning

    Keith Fiske <keith@omniti.com> — 2017-04-04T21:22:14Z

    On Tue, Apr 4, 2017 at 9:30 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello,
    >
    > Please find attached an updated patch.
    > Following has been accomplished in this update:
    >
    > 1. A new partition can be added after default partition if there are no
    > conflicting rows in default partition.
    > 2. Solved the crash reported earlier.
    >
    > Thank you,
    > Rahila Syed
    >
    >
    > --
    > Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    > To make changes to your subscription:
    > http://www.postgresql.org/mailpref/pgsql-hackers
    >
    >
    Installed and compiled against commit
    60a0b2ec8943451186dfa22907f88334d97cb2e0 (Date: Tue Apr 4 12:36:15 2017
    -0400) without any issue
    
    However, running your original example, I'm getting this error
    
    keith@keith=# CREATE TABLE list_partitioned (
    keith(#     a int
    keith(# ) PARTITION BY LIST (a);
    CREATE TABLE
    Time: 4.933 ms
    keith@keith=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT);
    CREATE TABLE
    Time: 3.492 ms
    keith@keith=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES
    IN (4,5);
    ERROR:  unrecognized node type: 216
    Time: 0.979 ms
    
    Also, I'm still of the opinion that denying future partitions of values in
    the default would be a cause of confusion. In order to move the data out of
    the default and into a proper child it would require first removing that
    data from the default, storing it elsewhere, creating the child, then
    moving it back. If it's only a small amount of data it may not be a big
    deal, but if it's a large amount, that could cause quite a lot of
    contention if done in a single transaction. Either that or the user would
    have to deal with data existing in the table, disappearing, then
    reappearing again.
    
    This also makes it harder to migrate an existing table easily. Essentially
    no child tables for a large, existing data set could ever be created
    without going through one of the two situations above.
    
    However, thinking through this, I'm not sure I can see a solution without
    the global index support. If this restriction is removed, there's still an
    issue of data duplication after the necessary child table is added. So
    guess it's a matter of deciding which user experience is better for the
    moment?
    
    --
    Keith Fiske
    Database Administrator
    OmniTI Computer Consulting, Inc.
    http://www.keithf4.com
    
  19. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-05T05:29:08Z

    On 2017/04/05 6:22, Keith Fiske wrote:
    > On Tue, Apr 4, 2017 at 9:30 AM, Rahila Syed wrote:
    >> Please find attached an updated patch.
    >> Following has been accomplished in this update:
    >>
    >> 1. A new partition can be added after default partition if there are no
    >> conflicting rows in default partition.
    >> 2. Solved the crash reported earlier.
    >
    > Installed and compiled against commit
    > 60a0b2ec8943451186dfa22907f88334d97cb2e0 (Date: Tue Apr 4 12:36:15 2017
    > -0400) without any issue
    > 
    > However, running your original example, I'm getting this error
    > 
    > keith@keith=# CREATE TABLE list_partitioned (
    > keith(#     a int
    > keith(# ) PARTITION BY LIST (a);
    > CREATE TABLE
    > Time: 4.933 ms
    > keith@keith=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    > VALUES IN (DEFAULT);
    > CREATE TABLE
    > Time: 3.492 ms
    > keith@keith=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES
    > IN (4,5);
    > ERROR:  unrecognized node type: 216
    
    It seems like the new ExecPrepareCheck should be used in the place of
    ExecPrepareExpr in the code added in check_new_partition_bound().
    
    > Also, I'm still of the opinion that denying future partitions of values in
    > the default would be a cause of confusion. In order to move the data out of
    > the default and into a proper child it would require first removing that
    > data from the default, storing it elsewhere, creating the child, then
    > moving it back. If it's only a small amount of data it may not be a big
    > deal, but if it's a large amount, that could cause quite a lot of
    > contention if done in a single transaction. Either that or the user would
    > have to deal with data existing in the table, disappearing, then
    > reappearing again.
    >
    > This also makes it harder to migrate an existing table easily. Essentially
    > no child tables for a large, existing data set could ever be created
    > without going through one of the two situations above.
    
    I thought of the following possible way to allow future partitions when
    the default partition exists which might contain rows that belong to the
    newly created partition (unfortunately, nothing that we could implement at
    this point for v10):
    
    Suppose you want to add a new partition which will accept key=3 rows.
    
    1. If no default partition exists, we're done; no key=3 rows would have
       been accepted by any of the table's existing partitions, so no need to
       move any rows
    
    2. Default partition exists which might contain key=3 rows, which we'll
       need to move.  If we do this in the same transaction, as you say, it
       might result in unnecessary unavailability of table's data.  So, it's
       better to delegate that responsibility to a background process.  The
       current transaction will only add the new key=3 partition, so any key=3
       rows will be routed to the new partition from this point on.  But we
       haven't updated the default partition's constraint yet to say that it
       no longer contains key=3 rows (constraint that the planner consumes),
       so it will continue to be scanned for queries that request key=3 rows
       (there should be some metadata to indicate that the default partition's
       constraint is invalid), along with the new partition.
    
    3. A background process receives a "work item" requesting it to move all
       key=3 rows from the default partition heap to the new partition's heap.
       The movement occurs without causing the table to become unavailable;
       once all rows have been moved, we momentarily lock the table to update
       the default partition's constraint to mark it valid, so that it will
       no longer be accessed by queries that want to see key=3 rows.
    
    Regarding 2, there is a question of whether it should not be possible for
    the row movement to occur in the same transaction.  Somebody may want that
    to happen because they chose to run the command during a maintenance
    window, when the table's becoming unavailable is not an issue.  In that
    case, we need to think of the interface more carefully.
    
    Regarding 3, I think the new autovacuum work items infrastructure added by
    the following commit looks very promising:
    
    * BRIN auto-summarization *
    https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=7526e10224f0792201e99631567bbe44492bbde4
    
    > However, thinking through this, I'm not sure I can see a solution without
    > the global index support. If this restriction is removed, there's still an
    > issue of data duplication after the necessary child table is added. So
    > guess it's a matter of deciding which user experience is better for the
    > moment?
    
    I'm not sure about the fate of this particular patch for v10, but until we
    implement a solution to move rows and design appropriate interface for the
    same, we could error out if moving rows is required at all, like the patch
    does.
    
    Could you briefly elaborate why you think the lack global index support
    would be a problem in this regard?
    
    I agree that some design is required here to implement a solution
    redistribution of rows; not only in the context of supporting the notion
    of default partitions, but also to allow the feature to split/merge range
    (only?) partitions.  I'd like to work on the latter for v11 for which I
    would like to post a proposal soon; if anyone would like to collaborate
    (ideas, code, review), I look forward to.  (sorry for hijacking this thread.)
    
    Thanks,
    Amit
    
    
    
    
    
  20. Re: Adding support for Default partition in partitioning

    Rushabh Lathia <rushabh.lathia@gmail.com> — 2017-04-05T05:41:50Z

    On Wed, Apr 5, 2017 at 10:59 AM, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp
    > wrote:
    
    > On 2017/04/05 6:22, Keith Fiske wrote:
    > > On Tue, Apr 4, 2017 at 9:30 AM, Rahila Syed wrote:
    > >> Please find attached an updated patch.
    > >> Following has been accomplished in this update:
    > >>
    > >> 1. A new partition can be added after default partition if there are no
    > >> conflicting rows in default partition.
    > >> 2. Solved the crash reported earlier.
    > >
    > > Installed and compiled against commit
    > > 60a0b2ec8943451186dfa22907f88334d97cb2e0 (Date: Tue Apr 4 12:36:15 2017
    > > -0400) without any issue
    > >
    > > However, running your original example, I'm getting this error
    > >
    > > keith@keith=# CREATE TABLE list_partitioned (
    > > keith(#     a int
    > > keith(# ) PARTITION BY LIST (a);
    > > CREATE TABLE
    > > Time: 4.933 ms
    > > keith@keith=# CREATE TABLE part_default PARTITION OF list_partitioned
    > FOR
    > > VALUES IN (DEFAULT);
    > > CREATE TABLE
    > > Time: 3.492 ms
    > > keith@keith=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR
    > VALUES
    > > IN (4,5);
    > > ERROR:  unrecognized node type: 216
    >
    > It seems like the new ExecPrepareCheck should be used in the place of
    > ExecPrepareExpr in the code added in check_new_partition_bound().
    >
    > > Also, I'm still of the opinion that denying future partitions of values
    > in
    > > the default would be a cause of confusion. In order to move the data out
    > of
    > > the default and into a proper child it would require first removing that
    > > data from the default, storing it elsewhere, creating the child, then
    > > moving it back. If it's only a small amount of data it may not be a big
    > > deal, but if it's a large amount, that could cause quite a lot of
    > > contention if done in a single transaction. Either that or the user would
    > > have to deal with data existing in the table, disappearing, then
    > > reappearing again.
    > >
    > > This also makes it harder to migrate an existing table easily.
    > Essentially
    > > no child tables for a large, existing data set could ever be created
    > > without going through one of the two situations above.
    >
    > I thought of the following possible way to allow future partitions when
    > the default partition exists which might contain rows that belong to the
    > newly created partition (unfortunately, nothing that we could implement at
    > this point for v10):
    >
    > Suppose you want to add a new partition which will accept key=3 rows.
    >
    > 1. If no default partition exists, we're done; no key=3 rows would have
    >    been accepted by any of the table's existing partitions, so no need to
    >    move any rows
    >
    > 2. Default partition exists which might contain key=3 rows, which we'll
    >    need to move.  If we do this in the same transaction, as you say, it
    >    might result in unnecessary unavailability of table's data.  So, it's
    >    better to delegate that responsibility to a background process.  The
    >    current transaction will only add the new key=3 partition, so any key=3
    >    rows will be routed to the new partition from this point on.  But we
    >    haven't updated the default partition's constraint yet to say that it
    >    no longer contains key=3 rows (constraint that the planner consumes),
    >    so it will continue to be scanned for queries that request key=3 rows
    >    (there should be some metadata to indicate that the default partition's
    >    constraint is invalid), along with the new partition.
    >
    > 3. A background process receives a "work item" requesting it to move all
    >    key=3 rows from the default partition heap to the new partition's heap.
    >    The movement occurs without causing the table to become unavailable;
    >    once all rows have been moved, we momentarily lock the table to update
    >    the default partition's constraint to mark it valid, so that it will
    >    no longer be accessed by queries that want to see key=3 rows.
    >
    > Regarding 2, there is a question of whether it should not be possible for
    > the row movement to occur in the same transaction.  Somebody may want that
    > to happen because they chose to run the command during a maintenance
    > window, when the table's becoming unavailable is not an issue.  In that
    > case, we need to think of the interface more carefully.
    >
    > Regarding 3, I think the new autovacuum work items infrastructure added by
    > the following commit looks very promising:
    >
    > * BRIN auto-summarization *
    > https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=
    > 7526e10224f0792201e99631567bbe44492bbde4
    >
    > > However, thinking through this, I'm not sure I can see a solution without
    > > the global index support. If this restriction is removed, there's still
    > an
    > > issue of data duplication after the necessary child table is added. So
    > > guess it's a matter of deciding which user experience is better for the
    > > moment?
    >
    > I'm not sure about the fate of this particular patch for v10, but until we
    > implement a solution to move rows and design appropriate interface for the
    > same, we could error out if moving rows is required at all, like the patch
    > does.
    >
    >
    +1
    
    I agree about the future plan about the row movement, how that is I am
    not quite sure at this stage.
    
    I was thinking that CREATE new partition is the DDL command, so even
    if row-movement works with holding the lock on the new partition table,
    that should be fine. I am not quire sure, why row movement should be
    happen in the back-ground process.
    
    Of-course, one idea is that if someone don't want feature of row-movement,
    then we might add that under some GUC or may be as another option into
    the CREATE partition table.
    
    Could you briefly elaborate why you think the lack global index support
    > would be a problem in this regard?
    >
    > I agree that some design is required here to implement a solution
    > redistribution of rows; not only in the context of supporting the notion
    > of default partitions, but also to allow the feature to split/merge range
    > (only?) partitions.  I'd like to work on the latter for v11 for which I
    > would like to post a proposal soon; if anyone would like to collaborate
    > (ideas, code, review), I look forward to.  (sorry for hijacking this
    > thread.)
    >
    > Thanks,
    > Amit
    >
    >
    >
    
    
    -- 
    Rushabh Lathia
    
  21. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-05T07:28:50Z

    Hi,
    
    >However, running your original example, I'm getting this error
    Thank you for testing. Please find attached an updated patch which fixes
    the above.
    
    
    Thank you,
    Rahila Syed
    
  22. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-05T07:52:30Z

    On 2017/04/05 14:41, Rushabh Lathia wrote:
    > I agree about the future plan about the row movement, how that is I am
    > not quite sure at this stage.
    > 
    > I was thinking that CREATE new partition is the DDL command, so even
    > if row-movement works with holding the lock on the new partition table,
    > that should be fine. I am not quire sure, why row movement should be
    > happen in the back-ground process.
    
    I think to improve the availability of access to the partitioned table.
    
    Consider that the default partition may have gotten pretty large.
    Scanning it and moving rows to the newly added partition while holding an
    AccessExclusiveLock on the parent will block any and all of the concurrent
    activity on it until the row-movement is finished.  One may be prepared to
    pay this cost, for which there should definitely be an option to perform
    the row-movement in the same transaction (also possibly the default behavior).
    
    Thanks,
    Amit
    
    
    
    
    
  23. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-05T09:57:11Z

    Hello Amit,
    
    >Could you briefly elaborate why you think the lack global index support
    >would be a problem in this regard?
    I think following can happen if we allow rows satisfying the new partition
    to lie around in the
    default partition until background process moves it.
    Consider a scenario where partition key is a primary key and the data in
    the default partition is
    not yet moved into the newly added partition. If now, new data is added
    into the new partition
    which also exists(same key) in default partition there will be data
    duplication. If now
    we scan the partitioned table for that key(from both the default and new
    partition as we
    have not moved the rows) it will fetch the both rows.
    Unless we have global indexes for partitioned tables, there is chance of
    data duplication between
    child table added after default partition and the default partition.
    
    >Scanning it and moving rows to the newly added partition while holding an
    >AccessExclusiveLock on the parent will block any and all of the concurrent
    >activity on it until the row-movement is finished.
    Can you explain why this will require AccessExclusiveLock on parent and
    not just the default partition and newly added partition?
    
    Thank you,
    Rahila Syed
    
    
    On Wed, Apr 5, 2017 at 1:22 PM, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
    wrote:
    
    > On 2017/04/05 14:41, Rushabh Lathia wrote:
    > > I agree about the future plan about the row movement, how that is I am
    > > not quite sure at this stage.
    > >
    > > I was thinking that CREATE new partition is the DDL command, so even
    > > if row-movement works with holding the lock on the new partition table,
    > > that should be fine. I am not quire sure, why row movement should be
    > > happen in the back-ground process.
    >
    > I think to improve the availability of access to the partitioned table.
    >
    > Consider that the default partition may have gotten pretty large.
    > Scanning it and moving rows to the newly added partition while holding an
    > AccessExclusiveLock on the parent will block any and all of the concurrent
    > activity on it until the row-movement is finished.  One may be prepared to
    > pay this cost, for which there should definitely be an option to perform
    > the row-movement in the same transaction (also possibly the default
    > behavior).
    >
    > Thanks,
    > Amit
    >
    >
    >
    
  24. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-05T10:23:35Z

    Hi Rahila,
    
    On 2017/04/05 18:57, Rahila Syed wrote:
    > Hello Amit,
    > 
    >> Could you briefly elaborate why you think the lack global index support
    >> would be a problem in this regard?
    > I think following can happen if we allow rows satisfying the new partition
    > to lie around in the
    > default partition until background process moves it.
    > Consider a scenario where partition key is a primary key and the data in
    > the default partition is
    > not yet moved into the newly added partition. If now, new data is added
    > into the new partition
    > which also exists(same key) in default partition there will be data
    > duplication. If now
    > we scan the partitioned table for that key(from both the default and new
    > partition as we
    > have not moved the rows) it will fetch the both rows.
    > Unless we have global indexes for partitioned tables, there is chance of
    > data duplication between
    > child table added after default partition and the default partition.
    
    Ah, okay.  I think I wrote that question before even reading the next
    sentence in Keith's message ("there's still an issue of data duplication
    after the necessary child table is added.")
    
    Maybe we can disallow background row movement if such global constraint
    exists.
    
    >> Scanning it and moving rows to the newly added partition while holding an
    >> AccessExclusiveLock on the parent will block any and all of the concurrent
    >> activity on it until the row-movement is finished.
    > Can you explain why this will require AccessExclusiveLock on parent and
    > not just the default partition and newly added partition?
    
    Because we take an AccessExclusiveLock on the parent table when
    adding/removing a partition in general.  We do that because concurrent
    accessors of the parent table rely on its partition descriptor from not
    changing under them.
    
    Thanks,
    Amit
    
    
    
    
    
  25. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-05T15:19:31Z

    On Wed, Apr 5, 2017 at 5:57 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>Could you briefly elaborate why you think the lack global index support
    >>would be a problem in this regard?
    > I think following can happen if we allow rows satisfying the new partition
    > to lie around in the
    > default partition until background process moves it.
    > Consider a scenario where partition key is a primary key and the data in the
    > default partition is
    > not yet moved into the newly added partition. If now, new data is added into
    > the new partition
    > which also exists(same key) in default partition there will be data
    > duplication. If now
    > we scan the partitioned table for that key(from both the default and new
    > partition as we
    > have not moved the rows) it will fetch the both rows.
    > Unless we have global indexes for partitioned tables, there is chance of
    > data duplication between
    > child table added after default partition and the default partition.
    
    Yes, I think it would be completely crazy to try to migrate the data
    in the background:
    
    - The migration might never complete because of a UNIQUE or CHECK
    constraint on the partition to which rows are being migrated.
    
    - Even if the migration eventually succeeded, such a design abandons
    all hope of making INSERT .. ON CONFLICT DO NOTHING work sensibly
    while the migration is in progress, unless the new partition has no
    UNIQUE constraints.
    
    - Partition-wise join and partition-wise aggregate would need to have
    special case handling for the case of an unfinished migration, as
    would any user code that accesses partitions directly.
    
    - More generally, I think users expect that when a DDL command
    finishes execution, it's done all of the work that there is to do (or
    at the very least, that any remaining work has no user-visible
    consequences, which would not be the case here).
    
    IMV, the question of whether we have efficient ways to move data
    around between partitions is somewhat separate from the question of
    whether partitions can be defined in a certain way in the first place.
    The problems that Keith refers to upthread already exist for
    subpartitioning; you've got to detach the old partition, create a new
    one, and then reinsert the data.  And for partitioning an
    unpartitioned table: create a replacement table, insert all the data,
    substitute it for the original table.  The fact that we have these
    limitation is not good, but we're not going to rip out partitioning
    entirely because we don't have clever ways of migrating the data in
    those cases, and the proposed behavior here is not any worse.
    
    Also, waiting for those problems to get fixed might be waiting for
    Godot.  I'm not really all that sanguine about our chances of coming
    up with a really nice way of handling these cases.  In a designed
    based on table inheritance, you can leave it murky where certain data
    is supposed to end up and migrate it on-line and you might get away
    with that, but a major point of having declarative partitioning at all
    is to remove that sort of murkiness.  It's probably not that hard to
    come up with a command that locks the parent and moves data around via
    full table scans, but I'm not sure how far that really gets us; you
    could do the same thing easily enough with a sequence of commands
    generated via a script.  And being able to do this in a general way
    without a full table lock looks pretty hard - it doesn't seem
    fundamentally different from trying to perform a table-rewriting
    operation like CLUSTER without a full table lock, which we also don't
    support.  The executor is not built to cope with any aspect of the
    table definition shifting under it, and that includes the set of child
    tables with are partitions of the table mentioned in the query.  Maybe
    the executor can be taught to survive such definitional changes at
    least in limited cases, but that's a much different project than
    allowing default partitions.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  26. Re: Adding support for Default partition in partitioning

    Keith Fiske <keith@omniti.com> — 2017-04-05T18:51:32Z

    On Wed, Apr 5, 2017 at 11:19 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Wed, Apr 5, 2017 at 5:57 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > >>Could you briefly elaborate why you think the lack global index support
    > >>would be a problem in this regard?
    > > I think following can happen if we allow rows satisfying the new
    > partition
    > > to lie around in the
    > > default partition until background process moves it.
    > > Consider a scenario where partition key is a primary key and the data in
    > the
    > > default partition is
    > > not yet moved into the newly added partition. If now, new data is added
    > into
    > > the new partition
    > > which also exists(same key) in default partition there will be data
    > > duplication. If now
    > > we scan the partitioned table for that key(from both the default and new
    > > partition as we
    > > have not moved the rows) it will fetch the both rows.
    > > Unless we have global indexes for partitioned tables, there is chance of
    > > data duplication between
    > > child table added after default partition and the default partition.
    >
    > Yes, I think it would be completely crazy to try to migrate the data
    > in the background:
    >
    > - The migration might never complete because of a UNIQUE or CHECK
    > constraint on the partition to which rows are being migrated.
    >
    > - Even if the migration eventually succeeded, such a design abandons
    > all hope of making INSERT .. ON CONFLICT DO NOTHING work sensibly
    > while the migration is in progress, unless the new partition has no
    > UNIQUE constraints.
    >
    > - Partition-wise join and partition-wise aggregate would need to have
    > special case handling for the case of an unfinished migration, as
    > would any user code that accesses partitions directly.
    >
    > - More generally, I think users expect that when a DDL command
    > finishes execution, it's done all of the work that there is to do (or
    > at the very least, that any remaining work has no user-visible
    > consequences, which would not be the case here).
    >
    > IMV, the question of whether we have efficient ways to move data
    > around between partitions is somewhat separate from the question of
    > whether partitions can be defined in a certain way in the first place.
    > The problems that Keith refers to upthread already exist for
    > subpartitioning; you've got to detach the old partition, create a new
    > one, and then reinsert the data.  And for partitioning an
    > unpartitioned table: create a replacement table, insert all the data,
    > substitute it for the original table.  The fact that we have these
    > limitation is not good, but we're not going to rip out partitioning
    > entirely because we don't have clever ways of migrating the data in
    > those cases, and the proposed behavior here is not any worse.
    >
    > Also, waiting for those problems to get fixed might be waiting for
    > Godot.  I'm not really all that sanguine about our chances of coming
    > up with a really nice way of handling these cases.  In a designed
    > based on table inheritance, you can leave it murky where certain data
    > is supposed to end up and migrate it on-line and you might get away
    > with that, but a major point of having declarative partitioning at all
    > is to remove that sort of murkiness.  It's probably not that hard to
    > come up with a command that locks the parent and moves data around via
    > full table scans, but I'm not sure how far that really gets us; you
    > could do the same thing easily enough with a sequence of commands
    > generated via a script.  And being able to do this in a general way
    > without a full table lock looks pretty hard - it doesn't seem
    > fundamentally different from trying to perform a table-rewriting
    > operation like CLUSTER without a full table lock, which we also don't
    > support.  The executor is not built to cope with any aspect of the
    > table definition shifting under it, and that includes the set of child
    > tables with are partitions of the table mentioned in the query.  Maybe
    > the executor can be taught to survive such definitional changes at
    > least in limited cases, but that's a much different project than
    > allowing default partitions.
    >
    > --
    > Robert Haas
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
    Confirmed that v5 patch works with examples given in the original post but
    segfaulted when I tried the examples I used in my blog post (taken from the
    documentation at the time I wrote it).
    https://www.keithf4.com/postgresql-10-built-in-partitioning/
    
    keith@keith=# drop table cities;
    DROP TABLE
    Time: 6.055 ms
    keith@keith=# CREATE TABLE cities (
        city_id         bigserial not null,
        name         text not null,
        population   int
    ) PARTITION BY LIST (initcap(name));
    CREATE TABLE
    Time: 7.130 ms
    keith@keith=# CREATE TABLE cities_west
        PARTITION OF cities (
        CONSTRAINT city_id_nonzero CHECK (city_id != 0)
    ) FOR VALUES IN ('Los Angeles', 'San Francisco');
    CREATE TABLE
    Time: 6.690 ms
    keith@keith=# CREATE TABLE cities_default
    keith-#     PARTITION OF cities FOR VALUES IN (DEFAULT);
    server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
    The connection to the server was lost. Attempting reset: WARNING:
    terminating connection because of crash of another server process
    DETAIL:  The postmaster has commanded this server process to roll back the
    current transaction and exit, because another server process exited
    abnormally and possibly corrupted shared memory.
    HINT:  In a moment you should be able to reconnect to the database and
    repeat your command.
    Failed.
    Time: 387.887 ms
    
    After reading responses, I think I'd be fine with how Rahila implemented
    this with disallowing the child until the data is removed from the default
    if this would allow it to be included in v10. As was mentioned, there just
    doesn't seem to be a way to easily handle the data conflicts cleanly at
    this time, but I think the value of the default to be able to catch
    accidental data vs returning an error is worth it. It also at least gives a
    slightly easier migration path vs having to migrate to a completely new
    table. Any chance this could be adapted for range partitioning as well? I'd
    be happy to create some pgtap tests with pg_partman for this then to make
    sure it works.
    
    Only issue I see with this, and I'm not sure if it is an issue, is what
    happens to that default constraint clause when 1000s of partitions start
    getting added? From what I gather the default's constraint is built based
    off the cumulative opposite of all other child constraints. I don't
    understand the code well enough to see what it's actually doing, but if
    there are no gaps, is the method used smart enough to aggregate all the
    child constraints to make a simpler constraint that is simply outside the
    current min/max boundaries? If so, for serial/time range partitioning this
    should typically work out fine since there are rarely gaps. This actually
    seems more of an issue for list partitioning where each child is a distinct
    value or range of values that are completely arbitrary. Won't that check
    and re-evaluation of the default's constraint just get worse and worse as
    more children are added? Is there really even a need for the default to
    have an opposite constraint like this? Not sure on how the planner works
    with partitioning now, but wouldn't it be better to first check all
    non-default children for a match the same as it does now without a default
    and, failing that, then route to the default if one is declared? The
    default should accept any data then so I don't see the need for the
    constraint unless it's required for the current implementation. If that's
    the case, could that be changed?
    
    Keith
    
  27. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-06T01:10:19Z

    On 2017/04/06 0:19, Robert Haas wrote:
    > On Wed, Apr 5, 2017 at 5:57 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>> Could you briefly elaborate why you think the lack global index support
    >>> would be a problem in this regard?
    >> I think following can happen if we allow rows satisfying the new partition
    >> to lie around in the
    >> default partition until background process moves it.
    >> Consider a scenario where partition key is a primary key and the data in the
    >> default partition is
    >> not yet moved into the newly added partition. If now, new data is added into
    >> the new partition
    >> which also exists(same key) in default partition there will be data
    >> duplication. If now
    >> we scan the partitioned table for that key(from both the default and new
    >> partition as we
    >> have not moved the rows) it will fetch the both rows.
    >> Unless we have global indexes for partitioned tables, there is chance of
    >> data duplication between
    >> child table added after default partition and the default partition.
    > 
    > Yes, I think it would be completely crazy to try to migrate the data
    > in the background:
    > 
    > - The migration might never complete because of a UNIQUE or CHECK
    > constraint on the partition to which rows are being migrated.
    > 
    > - Even if the migration eventually succeeded, such a design abandons
    > all hope of making INSERT .. ON CONFLICT DO NOTHING work sensibly
    > while the migration is in progress, unless the new partition has no
    > UNIQUE constraints.
    > 
    > - Partition-wise join and partition-wise aggregate would need to have
    > special case handling for the case of an unfinished migration, as
    > would any user code that accesses partitions directly.
    > 
    > - More generally, I think users expect that when a DDL command
    > finishes execution, it's done all of the work that there is to do (or
    > at the very least, that any remaining work has no user-visible
    > consequences, which would not be the case here).
    
    OK, I realize the background migration was a poorly thought out idea.  And
    a *first* version that will handle the row-movement should be doing that
    as part of the same command anyway.
    
    > IMV, the question of whether we have efficient ways to move data
    > around between partitions is somewhat separate from the question of
    > whether partitions can be defined in a certain way in the first place.
    > The problems that Keith refers to upthread already exist for
    > subpartitioning; you've got to detach the old partition, create a new
    > one, and then reinsert the data.  And for partitioning an
    > unpartitioned table: create a replacement table, insert all the data,
    > substitute it for the original table.  The fact that we have these
    > limitation is not good, but we're not going to rip out partitioning
    > entirely because we don't have clever ways of migrating the data in
    > those cases, and the proposed behavior here is not any worse.
    >
    > Also, waiting for those problems to get fixed might be waiting for
    > Godot.  I'm not really all that sanguine about our chances of coming
    > up with a really nice way of handling these cases.  In a designed
    > based on table inheritance, you can leave it murky where certain data
    > is supposed to end up and migrate it on-line and you might get away
    > with that, but a major point of having declarative partitioning at all
    > is to remove that sort of murkiness.  It's probably not that hard to
    > come up with a command that locks the parent and moves data around via
    > full table scans, but I'm not sure how far that really gets us; you
    > could do the same thing easily enough with a sequence of commands
    > generated via a script.  And being able to do this in a general way
    > without a full table lock looks pretty hard - it doesn't seem
    > fundamentally different from trying to perform a table-rewriting
    > operation like CLUSTER without a full table lock, which we also don't
    > support.  The executor is not built to cope with any aspect of the
    > table definition shifting under it, and that includes the set of child
    > tables with are partitions of the table mentioned in the query.  Maybe
    > the executor can be taught to survive such definitional changes at
    > least in limited cases, but that's a much different project than
    > allowing default partitions.
    
    Agreed.
    
    Thanks,
    Amit
    
    
    
    
    
  28. Re: Adding support for Default partition in partitioning

    Keith Fiske <keith@omniti.com> — 2017-04-06T04:08:36Z

    On Wed, Apr 5, 2017 at 2:51 PM, Keith Fiske <keith@omniti.com> wrote:
    
    >
    >
    > Only issue I see with this, and I'm not sure if it is an issue, is what
    > happens to that default constraint clause when 1000s of partitions start
    > getting added? From what I gather the default's constraint is built based
    > off the cumulative opposite of all other child constraints. I don't
    > understand the code well enough to see what it's actually doing, but if
    > there are no gaps, is the method used smart enough to aggregate all the
    > child constraints to make a simpler constraint that is simply outside the
    > current min/max boundaries? If so, for serial/time range partitioning this
    > should typically work out fine since there are rarely gaps. This actually
    > seems more of an issue for list partitioning where each child is a distinct
    > value or range of values that are completely arbitrary. Won't that check
    > and re-evaluation of the default's constraint just get worse and worse as
    > more children are added? Is there really even a need for the default to
    > have an opposite constraint like this? Not sure on how the planner works
    > with partitioning now, but wouldn't it be better to first check all
    > non-default children for a match the same as it does now without a default
    > and, failing that, then route to the default if one is declared? The
    > default should accept any data then so I don't see the need for the
    > constraint unless it's required for the current implementation. If that's
    > the case, could that be changed?
    >
    > Keith
    >
    
    Actually, thinking on this more, I realized this does again come back to
    the lack of a global index. Without the constraint, data could be put
    directly into the default that could technically conflict with the
    partition scheme elsewhere. Perhaps, instead of the constraint, inserts
    directly to the default could be prevented on the user level. Writing to
    valid children directly certainly has its place, but been thinking about
    it, and I can't see any reason why one would ever want to write directly to
    the default. It's use case seems to be around being a sort of temporary
    storage until that data can be moved to a valid location. Would still need
    to allow removal of data, though.
    
    Not sure if that's even a workable solution. Just trying to think of ways
    around the current limitations and still allow this feature.
    
  29. Re: Adding support for Default partition in partitioning

    Rushabh Lathia <rushabh.lathia@gmail.com> — 2017-04-06T05:17:13Z

    On 2017/04/06 0:19, Robert Haas wrote:
    > On Wed, Apr 5, 2017 at 5:57 AM, Rahila Syed <rahilasyed90@gmail.com>
    wrote:
    >>> Could you briefly elaborate why you think the lack global index support
    >>> would be a problem in this regard?
    >> I think following can happen if we allow rows satisfying the new
    partition
    >> to lie around in the
    >> default partition until background process moves it.
    >> Consider a scenario where partition key is a primary key and the data in
    the
    >> default partition is
    >> not yet moved into the newly added partition. If now, new data is added
    into
    >> the new partition
    >> which also exists(same key) in default partition there will be data
    >> duplication. If now
    >> we scan the partitioned table for that key(from both the default and new
    >> partition as we
    >> have not moved the rows) it will fetch the both rows.
    >> Unless we have global indexes for partitioned tables, there is chance of
    >> data duplication between
    >> child table added after default partition and the default partition.
    >
    > Yes, I think it would be completely crazy to try to migrate the data
    > in the background:
    >
    > - The migration might never complete because of a UNIQUE or CHECK
    > constraint on the partition to which rows are being migrated.
    >
    > - Even if the migration eventually succeeded, such a design abandons
    > all hope of making INSERT .. ON CONFLICT DO NOTHING work sensibly
    > while the migration is in progress, unless the new partition has no
    > UNIQUE constraints.
    >
    > - Partition-wise join and partition-wise aggregate would need to have
    > special case handling for the case of an unfinished migration, as
    > would any user code that accesses partitions directly.
    >
    > - More generally, I think users expect that when a DDL command
    > finishes execution, it's done all of the work that there is to do (or
    > at the very least, that any remaining work has no user-visible
    > consequences, which would not be the case here).
    
    Thanks Robert for this explanation. This makes it more clear, why row
    movement by background is not sensible idea.
    
    On Thu, Apr 6, 2017 at 9:38 AM, Keith Fiske <keith@omniti.com> wrote:
    
    >
    > On Wed, Apr 5, 2017 at 2:51 PM, Keith Fiske <keith@omniti.com> wrote:
    >
    >>
    >>
    >> Only issue I see with this, and I'm not sure if it is an issue, is what
    >> happens to that default constraint clause when 1000s of partitions start
    >> getting added? From what I gather the default's constraint is built based
    >> off the cumulative opposite of all other child constraints. I don't
    >> understand the code well enough to see what it's actually doing, but if
    >> there are no gaps, is the method used smart enough to aggregate all the
    >> child constraints to make a simpler constraint that is simply outside the
    >> current min/max boundaries? If so, for serial/time range partitioning this
    >> should typically work out fine since there are rarely gaps. This actually
    >> seems more of an issue for list partitioning where each child is a distinct
    >> value or range of values that are completely arbitrary. Won't that check
    >> and re-evaluation of the default's constraint just get worse and worse as
    >> more children are added? Is there really even a need for the default to
    >> have an opposite constraint like this? Not sure on how the planner works
    >> with partitioning now, but wouldn't it be better to first check all
    >> non-default children for a match the same as it does now without a default
    >> and, failing that, then route to the default if one is declared? The
    >> default should accept any data then so I don't see the need for the
    >> constraint unless it's required for the current implementation. If that's
    >> the case, could that be changed?
    >>
    >> Keith
    >>
    >
    > Actually, thinking on this more, I realized this does again come back to
    > the lack of a global index. Without the constraint, data could be put
    > directly into the default that could technically conflict with the
    > partition scheme elsewhere. Perhaps, instead of the constraint, inserts
    > directly to the default could be prevented on the user level. Writing to
    > valid children directly certainly has its place, but been thinking about
    > it, and I can't see any reason why one would ever want to write directly to
    > the default. It's use case seems to be around being a sort of temporary
    > storage until that data can be moved to a valid location. Would still need
    > to allow removal of data, though.
    >
    > Not sure if that's even a workable solution. Just trying to think of ways
    > around the current limitations and still allow this feature.
    >
    
    I like the idea about having DEFAULT partition for the range partition.
    With the
    way partition is designed it can have holes into range partition. I think
    DEFAULT
    for the range partition is a good idea, generally when the range having
    holes. When
    range is serial then of course DEFAULT partition doen't much sense.
    
    Regarda,
    
    Rushabh Lathia
    www.EnterpriseDB.com
    
  30. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-06T05:18:51Z

    On 2017/04/06 13:08, Keith Fiske wrote:
    > On Wed, Apr 5, 2017 at 2:51 PM, Keith Fiske wrote:
    >> Only issue I see with this, and I'm not sure if it is an issue, is what
    >> happens to that default constraint clause when 1000s of partitions start
    >> getting added? From what I gather the default's constraint is built based
    >> off the cumulative opposite of all other child constraints. I don't
    >> understand the code well enough to see what it's actually doing, but if
    >> there are no gaps, is the method used smart enough to aggregate all the
    >> child constraints to make a simpler constraint that is simply outside the
    >> current min/max boundaries? If so, for serial/time range partitioning this
    >> should typically work out fine since there are rarely gaps. This actually
    >> seems more of an issue for list partitioning where each child is a distinct
    >> value or range of values that are completely arbitrary. Won't that check
    >> and re-evaluation of the default's constraint just get worse and worse as
    >> more children are added? Is there really even a need for the default to
    >> have an opposite constraint like this? Not sure on how the planner works
    >> with partitioning now, but wouldn't it be better to first check all
    >> non-default children for a match the same as it does now without a default
    >> and, failing that, then route to the default if one is declared? The
    >> default should accept any data then so I don't see the need for the
    >> constraint unless it's required for the current implementation. If that's
    >> the case, could that be changed?
    
    Unless I misread your last sentence, I think there might be some
    confusion.  Currently, the partition constraint (think of these as you
    would of user-defined check constraints) is needed for two reasons: 1. to
    prevent direct insertion of rows into the default partition for which a
    non-default partition exists; no two partitions should ever have duplicate
    rows.  2. so that planner can use the constraint to determine if the
    default partition needs to be scanned for a query using constraint
    exclusion; no need, for example, to scan the default partition if the
    query requests only key=3 rows and a partition for the same exists (no
    other partition should have key=3 rows by definition, not even the
    default).  As things stand today, planner needs to look at every partition
    individually for using constraint exclusion to possibly exclude it, *even*
    with declarative partitioning and that would include the default partition.
    
    > Actually, thinking on this more, I realized this does again come back to
    > the lack of a global index. Without the constraint, data could be put
    > directly into the default that could technically conflict with the
    > partition scheme elsewhere. Perhaps, instead of the constraint, inserts
    > directly to the default could be prevented on the user level. Writing to
    > valid children directly certainly has its place, but been thinking about
    > it, and I can't see any reason why one would ever want to write directly to
    > the default. It's use case seems to be around being a sort of temporary
    > storage until that data can be moved to a valid location. Would still need
    > to allow removal of data, though.
    
    As mentioned above, the default partition will not allow directly
    inserting a row whose key maps to some existing (non-default) partition.
    
    As far as tuple-routing is concerned, it will choose the default partition
    only if no other partition is found for the key.  Tuple-routing doesn't
    use the partition constraints directly per se, like one of the two things
    mentioned above do.  One could say that tuple-routing assigns the incoming
    rows to partitions such that their individual partition constraints are
    not violated.
    
    Finally, we don't yet offer global guarantees for constraints like unique.
     The only guarantee that's in place is that no two partitions can contain
    the same partition key.
    
    Thanks,
    Amit
    
    
    
    
    
  31. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-06T11:30:24Z

    Hello,
    
    Thanks a lot for testing and reporting this. Please find attached an
    updated patch with the fix. The patch also contains a fix
    regarding operator used at the time of creating expression as default
    partition constraint. This was notified offlist by Amit Langote.
    
    Thank you,
    Rahila Syed
    
    
    On Thu, Apr 6, 2017 at 12:21 AM, Keith Fiske <keith@omniti.com> wrote:
    
    >
    > On Wed, Apr 5, 2017 at 11:19 AM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    >
    >> On Wed, Apr 5, 2017 at 5:57 AM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >> >>Could you briefly elaborate why you think the lack global index support
    >> >>would be a problem in this regard?
    >> > I think following can happen if we allow rows satisfying the new
    >> partition
    >> > to lie around in the
    >> > default partition until background process moves it.
    >> > Consider a scenario where partition key is a primary key and the data
    >> in the
    >> > default partition is
    >> > not yet moved into the newly added partition. If now, new data is added
    >> into
    >> > the new partition
    >> > which also exists(same key) in default partition there will be data
    >> > duplication. If now
    >> > we scan the partitioned table for that key(from both the default and new
    >> > partition as we
    >> > have not moved the rows) it will fetch the both rows.
    >> > Unless we have global indexes for partitioned tables, there is chance of
    >> > data duplication between
    >> > child table added after default partition and the default partition.
    >>
    >> Yes, I think it would be completely crazy to try to migrate the data
    >> in the background:
    >>
    >> - The migration might never complete because of a UNIQUE or CHECK
    >> constraint on the partition to which rows are being migrated.
    >>
    >> - Even if the migration eventually succeeded, such a design abandons
    >> all hope of making INSERT .. ON CONFLICT DO NOTHING work sensibly
    >> while the migration is in progress, unless the new partition has no
    >> UNIQUE constraints.
    >>
    >> - Partition-wise join and partition-wise aggregate would need to have
    >> special case handling for the case of an unfinished migration, as
    >> would any user code that accesses partitions directly.
    >>
    >> - More generally, I think users expect that when a DDL command
    >> finishes execution, it's done all of the work that there is to do (or
    >> at the very least, that any remaining work has no user-visible
    >> consequences, which would not be the case here).
    >>
    >> IMV, the question of whether we have efficient ways to move data
    >> around between partitions is somewhat separate from the question of
    >> whether partitions can be defined in a certain way in the first place.
    >> The problems that Keith refers to upthread already exist for
    >> subpartitioning; you've got to detach the old partition, create a new
    >> one, and then reinsert the data.  And for partitioning an
    >> unpartitioned table: create a replacement table, insert all the data,
    >> substitute it for the original table.  The fact that we have these
    >> limitation is not good, but we're not going to rip out partitioning
    >> entirely because we don't have clever ways of migrating the data in
    >> those cases, and the proposed behavior here is not any worse.
    >>
    >> Also, waiting for those problems to get fixed might be waiting for
    >> Godot.  I'm not really all that sanguine about our chances of coming
    >> up with a really nice way of handling these cases.  In a designed
    >> based on table inheritance, you can leave it murky where certain data
    >> is supposed to end up and migrate it on-line and you might get away
    >> with that, but a major point of having declarative partitioning at all
    >> is to remove that sort of murkiness.  It's probably not that hard to
    >> come up with a command that locks the parent and moves data around via
    >> full table scans, but I'm not sure how far that really gets us; you
    >> could do the same thing easily enough with a sequence of commands
    >> generated via a script.  And being able to do this in a general way
    >> without a full table lock looks pretty hard - it doesn't seem
    >> fundamentally different from trying to perform a table-rewriting
    >> operation like CLUSTER without a full table lock, which we also don't
    >> support.  The executor is not built to cope with any aspect of the
    >> table definition shifting under it, and that includes the set of child
    >> tables with are partitions of the table mentioned in the query.  Maybe
    >> the executor can be taught to survive such definitional changes at
    >> least in limited cases, but that's a much different project than
    >> allowing default partitions.
    >>
    >> --
    >> Robert Haas
    >> EnterpriseDB: http://www.enterprisedb.com
    >> The Enterprise PostgreSQL Company
    >>
    >
    > Confirmed that v5 patch works with examples given in the original post but
    > segfaulted when I tried the examples I used in my blog post (taken from the
    > documentation at the time I wrote it). https://www.keithf4.com/
    > postgresql-10-built-in-partitioning/
    >
    > keith@keith=# drop table cities;
    > DROP TABLE
    > Time: 6.055 ms
    > keith@keith=# CREATE TABLE cities (
    >     city_id         bigserial not null,
    >     name         text not null,
    >     population   int
    > ) PARTITION BY LIST (initcap(name));
    > CREATE TABLE
    > Time: 7.130 ms
    > keith@keith=# CREATE TABLE cities_west
    >     PARTITION OF cities (
    >     CONSTRAINT city_id_nonzero CHECK (city_id != 0)
    > ) FOR VALUES IN ('Los Angeles', 'San Francisco');
    > CREATE TABLE
    > Time: 6.690 ms
    > keith@keith=# CREATE TABLE cities_default
    > keith-#     PARTITION OF cities FOR VALUES IN (DEFAULT);
    > server closed the connection unexpectedly
    >     This probably means the server terminated abnormally
    >     before or while processing the request.
    > The connection to the server was lost. Attempting reset: WARNING:
    > terminating connection because of crash of another server process
    > DETAIL:  The postmaster has commanded this server process to roll back the
    > current transaction and exit, because another server process exited
    > abnormally and possibly corrupted shared memory.
    > HINT:  In a moment you should be able to reconnect to the database and
    > repeat your command.
    > Failed.
    > Time: 387.887 ms
    >
    > After reading responses, I think I'd be fine with how Rahila implemented
    > this with disallowing the child until the data is removed from the default
    > if this would allow it to be included in v10. As was mentioned, there just
    > doesn't seem to be a way to easily handle the data conflicts cleanly at
    > this time, but I think the value of the default to be able to catch
    > accidental data vs returning an error is worth it. It also at least gives a
    > slightly easier migration path vs having to migrate to a completely new
    > table. Any chance this could be adapted for range partitioning as well? I'd
    > be happy to create some pgtap tests with pg_partman for this then to make
    > sure it works.
    >
    > Only issue I see with this, and I'm not sure if it is an issue, is what
    > happens to that default constraint clause when 1000s of partitions start
    > getting added? From what I gather the default's constraint is built based
    > off the cumulative opposite of all other child constraints. I don't
    > understand the code well enough to see what it's actually doing, but if
    > there are no gaps, is the method used smart enough to aggregate all the
    > child constraints to make a simpler constraint that is simply outside the
    > current min/max boundaries? If so, for serial/time range partitioning this
    > should typically work out fine since there are rarely gaps. This actually
    > seems more of an issue for list partitioning where each child is a distinct
    > value or range of values that are completely arbitrary. Won't that check
    > and re-evaluation of the default's constraint just get worse and worse as
    > more children are added? Is there really even a need for the default to
    > have an opposite constraint like this? Not sure on how the planner works
    > with partitioning now, but wouldn't it be better to first check all
    > non-default children for a match the same as it does now without a default
    > and, failing that, then route to the default if one is declared? The
    > default should accept any data then so I don't see the need for the
    > constraint unless it's required for the current implementation. If that's
    > the case, could that be changed?
    >
    > Keith
    >
    
  32. Re: Adding support for Default partition in partitioning

    Keith Fiske <keith@omniti.com> — 2017-04-06T14:46:12Z

    On Thu, Apr 6, 2017 at 1:18 AM, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
    wrote:
    
    > On 2017/04/06 13:08, Keith Fiske wrote:
    > > On Wed, Apr 5, 2017 at 2:51 PM, Keith Fiske wrote:
    > >> Only issue I see with this, and I'm not sure if it is an issue, is what
    > >> happens to that default constraint clause when 1000s of partitions start
    > >> getting added? From what I gather the default's constraint is built
    > based
    > >> off the cumulative opposite of all other child constraints. I don't
    > >> understand the code well enough to see what it's actually doing, but if
    > >> there are no gaps, is the method used smart enough to aggregate all the
    > >> child constraints to make a simpler constraint that is simply outside
    > the
    > >> current min/max boundaries? If so, for serial/time range partitioning
    > this
    > >> should typically work out fine since there are rarely gaps. This
    > actually
    > >> seems more of an issue for list partitioning where each child is a
    > distinct
    > >> value or range of values that are completely arbitrary. Won't that check
    > >> and re-evaluation of the default's constraint just get worse and worse
    > as
    > >> more children are added? Is there really even a need for the default to
    > >> have an opposite constraint like this? Not sure on how the planner works
    > >> with partitioning now, but wouldn't it be better to first check all
    > >> non-default children for a match the same as it does now without a
    > default
    > >> and, failing that, then route to the default if one is declared? The
    > >> default should accept any data then so I don't see the need for the
    > >> constraint unless it's required for the current implementation. If
    > that's
    > >> the case, could that be changed?
    >
    > Unless I misread your last sentence, I think there might be some
    > confusion.  Currently, the partition constraint (think of these as you
    > would of user-defined check constraints) is needed for two reasons: 1. to
    > prevent direct insertion of rows into the default partition for which a
    > non-default partition exists; no two partitions should ever have duplicate
    > rows.  2. so that planner can use the constraint to determine if the
    > default partition needs to be scanned for a query using constraint
    > exclusion; no need, for example, to scan the default partition if the
    > query requests only key=3 rows and a partition for the same exists (no
    > other partition should have key=3 rows by definition, not even the
    > default).  As things stand today, planner needs to look at every partition
    > individually for using constraint exclusion to possibly exclude it, *even*
    > with declarative partitioning and that would include the default partition.
    >
    
    Forgot about constraint exclusion. My follow up email that you answered
    below was addressing the prevention of data to the default if there was no
    constraint on the default. I guess my main concern was with how manageable
    that cumulative opposite constraint of the default would be over time,
    especially with list partitioning. And also that it's smart enough to
    consolidate constraint conditions to simplify things if it's found that two
    or more conditions cover a continuous range.
    
    
    >
    > > Actually, thinking on this more, I realized this does again come back to
    > > the lack of a global index. Without the constraint, data could be put
    > > directly into the default that could technically conflict with the
    > > partition scheme elsewhere. Perhaps, instead of the constraint, inserts
    > > directly to the default could be prevented on the user level. Writing to
    > > valid children directly certainly has its place, but been thinking about
    > > it, and I can't see any reason why one would ever want to write directly
    > to
    > > the default. It's use case seems to be around being a sort of temporary
    > > storage until that data can be moved to a valid location. Would still
    > need
    > > to allow removal of data, though.
    >
    > As mentioned above, the default partition will not allow directly
    > inserting a row whose key maps to some existing (non-default) partition.
    >
    > As far as tuple-routing is concerned, it will choose the default partition
    > only if no other partition is found for the key.  Tuple-routing doesn't
    > use the partition constraints directly per se, like one of the two things
    > mentioned above do.  One could say that tuple-routing assigns the incoming
    > rows to partitions such that their individual partition constraints are
    > not violated.
    >
    >
    Finally, we don't yet offer global guarantees for constraints like unique.
    >  The only guarantee that's in place is that no two partitions can contain
    > the same partition key.
    >
    > Thanks,
    > Amit
    >
    >
    >
    
  33. Re: Adding support for Default partition in partitioning

    Keith Fiske <keith@omniti.com> — 2017-04-06T16:07:57Z

    On Thu, Apr 6, 2017 at 7:30 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello,
    >
    > Thanks a lot for testing and reporting this. Please find attached an
    > updated patch with the fix. The patch also contains a fix
    > regarding operator used at the time of creating expression as default
    > partition constraint. This was notified offlist by Amit Langote.
    >
    > Thank you,
    > Rahila Syed
    >
    >
    Could probably use some more extensive testing, but all examples I had on
    my previously mentioned blog post are now working.
    
    Keith
    
  34. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-04-10T14:42:43Z

    Hi Rahila,
    
    
    With your latest patch:
    
    Consider a case when a table is partitioned on a boolean key.
    
    Even when there are existing separate partitions for 'true' and
    
    'false', still default partition can be created.
    
    
    I think this should not be allowed.
    
    
    Consider following case:
    
    
    postgres=# CREATE TABLE list_partitioned (
    
        a bool
    
    ) PARTITION BY LIST (a);
    
    CREATE TABLE
    
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    ('false');
    
    CREATE TABLE
    
    postgres=# CREATE TABLE part_2 PARTITION OF list_partitioned FOR VALUES IN
    ('true');
    
    CREATE TABLE
    
    postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT);
    
    CREATE TABLE
    
    
    The creation of table part_default should have failed instead.
    
    
    Thanks,
    
    Jeevan Ladhe
    
    
    
    On Thu, Apr 6, 2017 at 9:37 PM, Keith Fiske <keith@omniti.com> wrote:
    
    >
    > On Thu, Apr 6, 2017 at 7:30 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    >
    >> Hello,
    >>
    >> Thanks a lot for testing and reporting this. Please find attached an
    >> updated patch with the fix. The patch also contains a fix
    >> regarding operator used at the time of creating expression as default
    >> partition constraint. This was notified offlist by Amit Langote.
    >>
    >> Thank you,
    >> Rahila Syed
    >>
    >>
    > Could probably use some more extensive testing, but all examples I had on
    > my previously mentioned blog post are now working.
    >
    > Keith
    >
    >
    
  35. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-04-10T14:51:32Z

    Hi Rahila,
    
    I tried to review the code, and here are some of my early comments:
    
    1.
    When I configure using "-Werror", I see unused variable in function
    DefineRelation:
    
    tablecmds.c: In function ‘DefineRelation’:
    tablecmds.c:761:17: error: unused variable ‘partdesc’
    [-Werror=unused-variable]
       PartitionDesc partdesc;
                     ^
    
    2.
    Typo in comment:
    + /*
    + * When adding a list partition after default partition, scan the
    + * default partiton for rows satisfying the new partition
    + * constraint. If found dont allow addition of a new partition.
    + * Otherwise continue with the creation of new  partition.
    + */
    
    partition
    don't
    
    3.
    I think instead of a period '.', it will be good if you can use semicolon
    ';'
    in following declaration similar to the comment for 'null_index'.
    
    + int def_index; /* Index of the default list partition. -1 for
    + * range partitioned tables */
    
    4.
    You may want to consider 80 column alignment for changes done in function
    get_qual_from_partbound, and other places as applicable.
    
    5.
    It would be good if the patch has some test coverage that explains what is
    being achieved, what kind of error handling is done etc.
    
    6.
    There are some places having code like following:
    
    + Node *value = lfirst(c);
      Const   *val = lfirst(c);
      PartitionListValue *list_value = NULL;
    
    + if (IsA(value, DefElem))
    
    The additional variable is not needed and you can call IsA on val itself.
    
    7.
    Also, in places like below where you are just trying to check for node is a
    DefaultElem, you can avoid an extra variable:
    
    + foreach(cell1, bspec->listdatums)
    + {
    + Node *value = lfirst(cell1);
    + if (IsA(value, DefElem))
    + {
    + def_elem = true;
    + *defid = inhrelid;
    + }
    
    Can be written as:
    + foreach(cell1, bspec->listdatums)
    + {
    + if (IsA(lfirst(cell1), DefElem))
    + {
    + def_elem = true;
    + *defid = inhrelid;
    + }
    + }
    
    
    Regards,
    Jeevan Ladhe
    
    
    
    On Mon, Apr 10, 2017 at 8:12 PM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com
    > wrote:
    
    > Hi Rahila,
    >
    >
    > With your latest patch:
    >
    > Consider a case when a table is partitioned on a boolean key.
    >
    > Even when there are existing separate partitions for 'true' and
    >
    > 'false', still default partition can be created.
    >
    >
    > I think this should not be allowed.
    >
    >
    > Consider following case:
    >
    >
    > postgres=# CREATE TABLE list_partitioned (
    >
    >     a bool
    >
    > ) PARTITION BY LIST (a);
    >
    > CREATE TABLE
    >
    > postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    > ('false');
    >
    > CREATE TABLE
    >
    > postgres=# CREATE TABLE part_2 PARTITION OF list_partitioned FOR VALUES IN
    > ('true');
    >
    > CREATE TABLE
    >
    > postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    > VALUES IN (DEFAULT);
    >
    > CREATE TABLE
    >
    >
    > The creation of table part_default should have failed instead.
    >
    >
    > Thanks,
    >
    > Jeevan Ladhe
    >
    >
    >
    > On Thu, Apr 6, 2017 at 9:37 PM, Keith Fiske <keith@omniti.com> wrote:
    >
    >>
    >> On Thu, Apr 6, 2017 at 7:30 AM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >>
    >>> Hello,
    >>>
    >>> Thanks a lot for testing and reporting this. Please find attached an
    >>> updated patch with the fix. The patch also contains a fix
    >>> regarding operator used at the time of creating expression as default
    >>> partition constraint. This was notified offlist by Amit Langote.
    >>>
    >>> Thank you,
    >>> Rahila Syed
    >>>
    >>>
    >> Could probably use some more extensive testing, but all examples I had on
    >> my previously mentioned blog post are now working.
    >>
    >> Keith
    >>
    >>
    >
    
  36. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-04-11T12:32:30Z

    On Mon, Apr 10, 2017 at 8:12 PM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > Hi Rahila,
    >
    >
    > With your latest patch:
    >
    > Consider a case when a table is partitioned on a boolean key.
    >
    > Even when there are existing separate partitions for 'true' and
    >
    > 'false', still default partition can be created.
    >
    >
    > I think this should not be allowed.
    
    Well, boolean columns can have "NULL" values which will go into
    default partition if no NULL partition exists. So, probably we should
    add check for NULL partition there.
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  37. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-04-11T13:41:33Z

    Hi Ashutosh,
    
    
    On Tue, Apr 11, 2017 at 6:02 PM, Ashutosh Bapat <
    ashutosh.bapat@enterprisedb.com> wrote:
    
    > On Mon, Apr 10, 2017 at 8:12 PM, Jeevan Ladhe
    > <jeevan.ladhe@enterprisedb.com> wrote:
    > > Hi Rahila,
    > >
    > >
    > > With your latest patch:
    > >
    > > Consider a case when a table is partitioned on a boolean key.
    > >
    > > Even when there are existing separate partitions for 'true' and
    > >
    > > 'false', still default partition can be created.
    > >
    > >
    > > I think this should not be allowed.
    >
    > Well, boolean columns can have "NULL" values which will go into
    > default partition if no NULL partition exists. So, probably we should
    > add check for NULL partition there.
    
    
    I have checked for NULLs too, and the default partition can be created even
    when there are partitions for each TRUE, FALSE and NULL.
    
    Consider the example below:
    
    postgres=# CREATE TABLE list_partitioned (
        a bool
    ) PARTITION BY LIST (a);
    CREATE TABLE
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    ('false');
    CREATE TABLE
    postgres=# CREATE TABLE part_2 PARTITION OF list_partitioned FOR VALUES IN
    ('true');
    CREATE TABLE
    postgres=# CREATE TABLE part_3 PARTITION OF list_partitioned FOR VALUES IN
    (null);
    CREATE TABLE
    postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT);
    CREATE TABLE
    
    Regards,
    Jeevan Ladhe
    
  38. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-12T18:39:11Z

    On Tue, Apr 11, 2017 at 9:41 AM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > I have checked for NULLs too, and the default partition can be created even
    > when there are partitions for each TRUE, FALSE and NULL.
    >
    > Consider the example below:
    >
    > postgres=# CREATE TABLE list_partitioned (
    >     a bool
    > ) PARTITION BY LIST (a);
    > CREATE TABLE
    > postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    > ('false');
    > CREATE TABLE
    > postgres=# CREATE TABLE part_2 PARTITION OF list_partitioned FOR VALUES IN
    > ('true');
    > CREATE TABLE
    > postgres=# CREATE TABLE part_3 PARTITION OF list_partitioned FOR VALUES IN
    > (null);
    > CREATE TABLE
    > postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    > VALUES IN (DEFAULT);
    > CREATE TABLE
    
    In my opinion, that's absolutely fine, and it would be very strange to
    try to prevent it.  The partitioning method shouldn't have specific
    knowledge of the properties of individual data types.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  39. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-12T18:41:34Z

    On Thu, Apr 6, 2017 at 1:17 AM, Rushabh Lathia <rushabh.lathia@gmail.com> wrote:
    > I like the idea about having DEFAULT partition for the range partition. With
    > the
    > way partition is designed it can have holes into range partition. I think
    > DEFAULT
    > for the range partition is a good idea, generally when the range having
    > holes. When
    > range is serial then of course DEFAULT partition doen't much sense.
    
    Yes, I like that idea, too.  I think the DEFAULT partition should be
    allowed to be created for either range or list partitioning regardless
    of whether we think there are any holes, but if you create a DEFAULT
    partition when there are no holes, you just won't be able to put any
    data into it.  It's silly, but it's not worth the code that it would
    take to try to prevent it.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  40. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-12T19:18:38Z

    On Thu, Apr 6, 2017 at 7:30 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    > Thanks a lot for testing and reporting this. Please find attached an updated
    > patch with the fix. The patch also contains a fix
    > regarding operator used at the time of creating expression as default
    > partition constraint. This was notified offlist by Amit Langote.
    
    I think that the syntax for this patch should probably be revised.
    Right now the proposal is for:
    
    CREATE TABLE .. PARTITION OF ... FOR VALUES IN (DEFAULT);
    
    But that's not a good idea for several reasons.  For one thing, you
    can also write FOR VALUES IN (DEFAULT, 5) or which isn't sensible.
    For another thing, this kind of syntax won't generalize to range
    partitioning, which we've talked about making this feature support.
    Maybe something like:
    
    CREATE TABLE .. PARTITION OF .. DEFAULT;
    
    This patch makes the assumption throughout that any DefElem represents
    the word DEFAULT, which is true in the patch as written but doesn't
    seem very future-proof.  I think the "def" in "DefElem" stands for
    "definition" or "define" or something like that, so this is actually
    pretty confusing.  Maybe we should introduce a dedicated node type to
    represent a default-specification in the parser grammar.  If not, then
    let's at least encapsulate the test a little better, e.g. by adding
    isDefaultPartitionBound() which tests not only IsA(..., DefElem) but
    also whether the name is DEFAULT as expected.  BTW, we typically use
    lower-case internally, so if we stick with this representation it
    should really be "default" not "DEFAULT".
    
    Useless hunk:
    
    +    bool        has_def;        /* Is there a default partition?
    Currently false
    +                                 * for a range partitioned table */
    +    int            def_index;        /* Index of the default list
    partition. -1 for
    +                                 * range partitioned tables */
    
    Why abbreviate "default" to def here?  Seems pointless.
    
    +                    if (found_def)
    +                    {
    +                        if (mapping[def_index] == -1)
    +                            mapping[def_index] = next_index++;
    +                    }
    
    Consider &&
    
    @@ -717,7 +754,6 @@ check_new_partition_bound(char *relname, Relation
    parent, Node *bound)
                             }
                         }
                     }
    -
                     break;
                 }
    
    +     * default partiton for rows satisfying the new partition
    
    Spelling.
    
    +     * constraint. If found dont allow addition of a new partition.
    
    Missing apostrophe.
    
    +        defrel = heap_open(defid, AccessShareLock);
    +        tupdesc = CreateTupleDescCopy(RelationGetDescr(defrel));
    +
    +        /* Build expression execution states for partition check quals */
    +        partqualstate = ExecPrepareCheck(partConstraint,
    +                        estate);
    +
    +        econtext = GetPerTupleExprContext(estate);
    +        snapshot = RegisterSnapshot(GetLatestSnapshot());
    
    Definitely not safe against concurrency, since AccessShareLock won't
    exclude somebody else's update.  In fact, it won't even cover somebody
    else's already-in-flight transaction.
    
    +                errmsg("new default partition constraint is violated
    by some row")));
    
    Normally in such cases we try to give more detail using
    ExecBuildSlotValueDescription.
    
    +    bool        is_def = true;
    
    This variable starts out true and is never set to any value other than
    true.  Just get rid of it and, in the one place where it is currently
    used, write "true".  That's shorter and clearer.
    
    +    inhoids = find_inheritance_children(RelationGetRelid(parent), NoLock);
    
    If it's actually safe to do this with no lock, there ought to be a
    comment with a very compelling explanation of why it's safe.
    
    +        boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
    +        bspec = (PartitionBoundSpec *)boundspec;
    
    There's not really a reason to cast the result of stringToNode() to
    Node * and then turn around and cast it to PartitionBoundSpec *.  Just
    cast it directly to whatever it needs to be.  And use the new castNode
    macro.
    
    +        foreach(cell1, bspec->listdatums)
    +        {
    +            Node *value = lfirst(cell1);
    +            if (IsA(value, DefElem))
    +            {
    +                def_elem = true;
    +                *defid = inhrelid;
    +            }
    +        }
    +        if (def_elem)
    +        {
    +            ReleaseSysCache(tuple);
    +            continue;
    +        }
    +        foreach(cell3, bspec->listdatums)
    +        {
    +            Node *value = lfirst(cell3);
    +            boundspecs = lappend(boundspecs, value);
    +        }
    +        ReleaseSysCache(tuple);
    +    }
    +    foreach(cell4, spec->listdatums)
    +    {
    +        Node *value = lfirst(cell4);
    +        boundspecs = lappend(boundspecs, value);
    +    }
    
    cell1, cell2, cell3, and cell4 are not very clear variable names.
    Between that and the lack of comments, this is not easy to understand.
    It's sort of spaghetti logic, too.  The if (def_elem) test continues
    early, but if the point is that the loop using cell3 shouldn't execute
    in that case, why not just put if (!def_elem) { foreach(cell3, ...) {
    ... } } instead of reiterating the ReleaseSysCache in two places?
    
    +                /* Collect bound spec nodes in a list. This is done
    if the partition is
    +                 * a default partition. In case of default partition,
    constraint is formed
    +                 * by performing <> operation over the partition
    constraints of the
    +                 * existing partitions.
    +                 */
    
    I doubt that handles NULLs properly.
    
    +                inhoids =
    find_inheritance_children(RelationGetRelid(parent), NoLock);
    
    Again, no lock?  Really?
    
    The logic which follows looks largely cut-and-pasted, which makes me
    think you need to do some refactoring here to make it more clear
    what's going on, so that you have the relevant logic in just one
    place.  It seems wrong anyway to shove all of this logic specific to
    the default case into get_qual_from_partbound() when the logic for the
    non-default case is inside get_qual_for_list.  Where there were 2
    lines of code before you've now got something like 30.
    
    +        if(get_negator(operoid) == InvalidOid)
    +            elog(ERROR, "no negator found for partition operator %u",
    +                 operoid);
    
    I really doubt that's OK.  elog() shouldn't be reachable, but this
    will be reachable if the partitioning operator does not have a
    negator.  And there's the NULL-handling issue I mentioned above, too.
    
    +            if (partdesc->boundinfo->has_def && key->strategy
    +                == PARTITION_STRATEGY_LIST)
    +                result = parent->indexes[partdesc->boundinfo->def_index];
    
    Testing for PARTITION_STRATEGY_LIST here seems unnecessary.  If
    has_def (or has_default, as it probably should be) isn't allowed for
    range partitions, then it's redundant; if it is allowed, then that
    case should be handled too.  Also, at this point we've already set
    *failed_at and *failed_slot; presumably you'd want to make this check
    before you get to that point.
    
    I suspect there are quite a few more problems here in addition to the
    ones mentioned above, but I don't think it makes sense to spend too
    much time searching for them until some of this basic stuff is cleaned
    up.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  41. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-24T09:10:24Z

    Hello,
    
    Thank you for reviewing.
    
    >But that's not a good idea for several reasons.  For one thing, you
    >can also write FOR VALUES IN (DEFAULT, 5) or which isn't sensible.
    >For another thing, this kind of syntax won't generalize to range
    >partitioning, which we've talked about making this feature support.
    >Maybe something like:
    
    >CREATE TABLE .. PARTITION OF .. DEFAULT;
    
    I agree that the syntax should be changed to also support range
    partitioning.
    
    Following can also be considered as it specifies more clearly that the
    partition holds default values.
    
    CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    
    >Maybe we should introduce a dedicated node type to
    >represent a default-specification in the parser grammar.  If not, then
    >let's at least encapsulate the test a little better, e.g. by adding
    >isDefaultPartitionBound() which tests not only IsA(..., DefElem) but
    >also whether the name is DEFAULT as expected.  BTW, we typically use
    >lower-case internally, so if we stick with this representation it
    >should really be "default" not "DEFAULT".
    
    isDefaultPartitionBound() function is created in the attached patch which
    checks for both node type and name.
    
    >Why abbreviate "default" to def here?  Seems pointless.
    Corrected in the attached.
    
    >Consider &&
    Fixed.
    
    >+     * default partiton for rows satisfying the new partition
    >Spelling.
    Fixed.
    
    >Missing apostrophe
    Fixed.
    
    >Definitely not safe against concurrency, since AccessShareLock won't
    >exclude somebody else's update.  In fact, it won't even cover somebody
    >else's already-in-flight transaction
    Changed it to AccessExclusiveLock
    
    >Normally in such cases we try to give more detail using
    >ExecBuildSlotValueDescription.
    This function is used in execMain.c and the error is being
    reported in partition.c.
    Do you mean the error reporting should be moved into execMain.c
    to use ExecBuildSlotValueDescription?
    
    >This variable starts out true and is never set to any value other than
    >true.  Just get rid of it and, in the one place where it is currently
    >used, write "true".  That's shorter and clearer.
    Fixed.
    
    >There's not really a reason to cast the result of stringToNode() to
    >Node * and then turn around and cast it to PartitionBoundSpec *.  Just
    >cast it directly to whatever it needs to be.  And use the new castNode
    >macro
    Fixed. castNode macro takes as input Node * whereas stringToNode() takes
    string.
    IIUC, castNode cant be used here.
    
    >The if (def_elem) test continues
    >early, but if the point is that the loop using cell3 shouldn't execute
    >in that case, why not just put if (!def_elem) { foreach(cell3, ...) {
    >... } } instead of reiterating the ReleaseSysCache in two places?
    Fixed in the attached.
    
    I will respond to further comments in following email.
    
    
    On Thu, Apr 13, 2017 at 12:48 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Thu, Apr 6, 2017 at 7:30 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > > Thanks a lot for testing and reporting this. Please find attached an
    > updated
    > > patch with the fix. The patch also contains a fix
    > > regarding operator used at the time of creating expression as default
    > > partition constraint. This was notified offlist by Amit Langote.
    >
    > I think that the syntax for this patch should probably be revised.
    > Right now the proposal is for:
    >
    > CREATE TABLE .. PARTITION OF ... FOR VALUES IN (DEFAULT);
    >
    > But that's not a good idea for several reasons.  For one thing, you
    > can also write FOR VALUES IN (DEFAULT, 5) or which isn't sensible.
    > For another thing, this kind of syntax won't generalize to range
    > partitioning, which we've talked about making this feature support.
    > Maybe something like:
    >
    > CREATE TABLE .. PARTITION OF .. DEFAULT;
    >
    > This patch makes the assumption throughout that any DefElem represents
    > the word DEFAULT, which is true in the patch as written but doesn't
    > seem very future-proof.  I think the "def" in "DefElem" stands for
    > "definition" or "define" or something like that, so this is actually
    > pretty confusing.  Maybe we should introduce a dedicated node type to
    > represent a default-specification in the parser grammar.  If not, then
    > let's at least encapsulate the test a little better, e.g. by adding
    > isDefaultPartitionBound() which tests not only IsA(..., DefElem) but
    > also whether the name is DEFAULT as expected.  BTW, we typically use
    > lower-case internally, so if we stick with this representation it
    > should really be "default" not "DEFAULT".
    >
    > Useless hunk:
    >
    > +    bool        has_def;        /* Is there a default partition?
    > Currently false
    > +                                 * for a range partitioned table */
    > +    int            def_index;        /* Index of the default list
    > partition. -1 for
    > +                                 * range partitioned tables */
    >
    > Why abbreviate "default" to def here?  Seems pointless.
    >
    > +                    if (found_def)
    > +                    {
    > +                        if (mapping[def_index] == -1)
    > +                            mapping[def_index] = next_index++;
    > +                    }
    >
    > Consider &&
    >
    > @@ -717,7 +754,6 @@ check_new_partition_bound(char *relname, Relation
    > parent, Node *bound)
    >                          }
    >                      }
    >                  }
    > -
    >                  break;
    >              }
    >
    > +     * default partiton for rows satisfying the new partition
    >
    > Spelling.
    >
    > +     * constraint. If found dont allow addition of a new partition.
    >
    > Missing apostrophe.
    >
    > +        defrel = heap_open(defid, AccessShareLock);
    > +        tupdesc = CreateTupleDescCopy(RelationGetDescr(defrel));
    > +
    > +        /* Build expression execution states for partition check quals */
    > +        partqualstate = ExecPrepareCheck(partConstraint,
    > +                        estate);
    > +
    > +        econtext = GetPerTupleExprContext(estate);
    > +        snapshot = RegisterSnapshot(GetLatestSnapshot());
    >
    > Definitely not safe against concurrency, since AccessShareLock won't
    > exclude somebody else's update.  In fact, it won't even cover somebody
    > else's already-in-flight transaction.
    >
    > +                errmsg("new default partition constraint is violated
    > by some row")));
    >
    > Normally in such cases we try to give more detail using
    > ExecBuildSlotValueDescription.
    >
    > +    bool        is_def = true;
    >
    > This variable starts out true and is never set to any value other than
    > true.  Just get rid of it and, in the one place where it is currently
    > used, write "true".  That's shorter and clearer.
    >
    > +    inhoids = find_inheritance_children(RelationGetRelid(parent),
    > NoLock);
    >
    > If it's actually safe to do this with no lock, there ought to be a
    > comment with a very compelling explanation of why it's safe.
    >
    > +        boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
    > +        bspec = (PartitionBoundSpec *)boundspec;
    >
    > There's not really a reason to cast the result of stringToNode() to
    > Node * and then turn around and cast it to PartitionBoundSpec *.  Just
    > cast it directly to whatever it needs to be.  And use the new castNode
    > macro.
    >
    > +        foreach(cell1, bspec->listdatums)
    > +        {
    > +            Node *value = lfirst(cell1);
    > +            if (IsA(value, DefElem))
    > +            {
    > +                def_elem = true;
    > +                *defid = inhrelid;
    > +            }
    > +        }
    > +        if (def_elem)
    > +        {
    > +            ReleaseSysCache(tuple);
    > +            continue;
    > +        }
    > +        foreach(cell3, bspec->listdatums)
    > +        {
    > +            Node *value = lfirst(cell3);
    > +            boundspecs = lappend(boundspecs, value);
    > +        }
    > +        ReleaseSysCache(tuple);
    > +    }
    > +    foreach(cell4, spec->listdatums)
    > +    {
    > +        Node *value = lfirst(cell4);
    > +        boundspecs = lappend(boundspecs, value);
    > +    }
    >
    > cell1, cell2, cell3, and cell4 are not very clear variable names.
    > Between that and the lack of comments, this is not easy to understand.
    > It's sort of spaghetti logic, too.  The if (def_elem) test continues
    > early, but if the point is that the loop using cell3 shouldn't execute
    > in that case, why not just put if (!def_elem) { foreach(cell3, ...) {
    > ... } } instead of reiterating the ReleaseSysCache in two places?
    >
    > +                /* Collect bound spec nodes in a list. This is done
    > if the partition is
    > +                 * a default partition. In case of default partition,
    > constraint is formed
    > +                 * by performing <> operation over the partition
    > constraints of the
    > +                 * existing partitions.
    > +                 */
    >
    > I doubt that handles NULLs properly.
    >
    > +                inhoids =
    > find_inheritance_children(RelationGetRelid(parent), NoLock);
    >
    > Again, no lock?  Really?
    >
    > The logic which follows looks largely cut-and-pasted, which makes me
    > think you need to do some refactoring here to make it more clear
    > what's going on, so that you have the relevant logic in just one
    > place.  It seems wrong anyway to shove all of this logic specific to
    > the default case into get_qual_from_partbound() when the logic for the
    > non-default case is inside get_qual_for_list.  Where there were 2
    > lines of code before you've now got something like 30.
    >
    > +        if(get_negator(operoid) == InvalidOid)
    > +            elog(ERROR, "no negator found for partition operator %u",
    > +                 operoid);
    >
    > I really doubt that's OK.  elog() shouldn't be reachable, but this
    > will be reachable if the partitioning operator does not have a
    > negator.  And there's the NULL-handling issue I mentioned above, too.
    >
    > +            if (partdesc->boundinfo->has_def && key->strategy
    > +                == PARTITION_STRATEGY_LIST)
    > +                result = parent->indexes[partdesc->boundinfo->def_index];
    >
    > Testing for PARTITION_STRATEGY_LIST here seems unnecessary.  If
    > has_def (or has_default, as it probably should be) isn't allowed for
    > range partitions, then it's redundant; if it is allowed, then that
    > case should be handled too.  Also, at this point we've already set
    > *failed_at and *failed_slot; presumably you'd want to make this check
    > before you get to that point.
    >
    > I suspect there are quite a few more problems here in addition to the
    > ones mentioned above, but I don't think it makes sense to spend too
    > much time searching for them until some of this basic stuff is cleaned
    > up.
    >
    > --
    > Robert Haas
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  42. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-24T10:54:00Z

    On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    > Following can also be considered as it specifies more clearly that the
    > partition holds default values.
    >
    > CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    
    Yes, that could be done.  But I don't think it's correct to say that
    the partition holds default values.  Let's back up and ask what the
    word "default" means.  The relevant definition (according to Google or
    whoever they stole it from) is:
    
    a preselected option adopted by a computer program or other mechanism
    when no alternative is specified by the user or programmer.
    
    So, a default *value* is the value that is used when no alternative is
    specified by the user or programmer. We have that concept, but it's
    not what we're talking about here: that's configured by applying the
    DEFAULT property to a column.  Here, we're talking about the default
    *partition*, or in other words the *partition* that is used when no
    alternative is specified by the user or programmer.  So, that's why I
    proposed the syntax I did.  The partition doesn't contain default
    values; it is itself a default.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  43. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-04-24T12:14:57Z

    On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    > On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >> Following can also be considered as it specifies more clearly that the
    >> partition holds default values.
    >>
    >> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    >
    > Yes, that could be done.  But I don't think it's correct to say that
    > the partition holds default values.  Let's back up and ask what the
    > word "default" means.  The relevant definition (according to Google or
    > whoever they stole it from) is:
    >
    > a preselected option adopted by a computer program or other mechanism
    > when no alternative is specified by the user or programmer.
    >
    > So, a default *value* is the value that is used when no alternative is
    > specified by the user or programmer. We have that concept, but it's
    > not what we're talking about here: that's configured by applying the
    > DEFAULT property to a column.  Here, we're talking about the default
    > *partition*, or in other words the *partition* that is used when no
    > alternative is specified by the user or programmer.  So, that's why I
    > proposed the syntax I did.  The partition doesn't contain default
    > values; it is itself a default.
    
    Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more natural.
    
    
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  44. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-04-24T18:38:30Z

    Hi Rahila,
    
    I tried to go through your v7 patch, and following are my comments:
    
    1.
    With -Werrors I see following compilation failure:
    
    parse_utilcmd.c: In function ‘transformPartitionBound’:
    parse_utilcmd.c:3309:4: error: implicit declaration of function
    ‘isDefaultPartitionBound’ [-Werror=implicit-function-declaration]
        if (!(isDefaultPartitionBound(value)))
        ^
    cc1: all warnings being treated as errors
    
    You need to include, "catalog/partitions.h".
    
    2.
    Once I made above change pass, I see following error:
    tablecmds.c: In function ‘DefineRelation’:
    tablecmds.c:762:17: error: unused variable ‘partdesc’
    [-Werror=unused-variable]
       PartitionDesc partdesc;
                     ^
    cc1: all warnings being treated as errors
    
    3.
    Please remove the extra line at the end of the function
    check_new_partition_bound:
    + MemoryContextSwitchTo(oldCxt);
    + heap_endscan(scan);
    + UnregisterSnapshot(snapshot);
    + heap_close(defrel, AccessExclusiveLock);
    + ExecDropSingleTupleTableSlot(tupslot);
    + }
    +
     }
    
    4.
    In generate_qual_for_defaultpart() you do not need 2 pointers for looping
    over
    bound specs:
    + ListCell   *cell1;
    + ListCell   *cell3;
    You can iterate twice using one pointer itself.
    
    Same is for:
    + ListCell   *cell2;
    + ListCell   *cell4;
    
    Similarly, in get_qual_from_partbound(), you can use one pointer below,
    instead of cell1 and cell3:
    + PartitionBoundSpec *bspec;
    + ListCell *cell1;
    + ListCell *cell3;
    
    5.
    Should this have a break in if block?
    + foreach(cell1, bspec->listdatums)
    + {
    + Node *value = lfirst(cell1);
    + if (isDefaultPartitionBound(value))
    + {
    + def_elem = true;
    + *defid = inhrelid;
    + }
    + }
    
    6.
    I am wondering, isn't it possible to retrieve the has_default and
    default_index
    here to find out if default partition exists and if exist then find it's oid
    using rd_partdesc, that would avoid above(7) loop to check if partition
    bound is
    default.
    
    7.
    The output of describe needs to be improved.
    Consider following case:
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    (4,5,4,4,4,6,2);
    ERROR:  relation "list_partitioned" does not exist
    postgres=# CREATE TABLE list_partitioned (
        a int
    ) PARTITION BY LIST (a);
    CREATE TABLE
    postgres=# CREATE TABLE part_1 PARTITION OF list_partitioned FOR VALUES IN
    (4,5,4,4,4,6,2);
    CREATE TABLE
    postgres=# CREATE TABLE part_default PARTITION OF list_partitioned FOR
    VALUES IN (DEFAULT, 3, DEFAULT, 3, DEFAULT);
    CREATE TABLE
    postgres=# \d+ part_1;
                                      Table "public.part_1"
     Column |  Type   | Collation | Nullable | Default | Storage | Stats target
    | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
     a      | integer |           |          |         | plain   |
     |
    Partition of: list_partitioned FOR VALUES IN (4, 5, 6, 2)
    
    postgres=# \d+ part_default;
                                   Table "public.part_default"
     Column |  Type   | Collation | Nullable | Default | Storage | Stats target
    | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
     a      | integer |           |          |         | plain   |
     |
    Partition of: list_partitioned FOR VALUES IN (DEFAULT3DEFAULTDEFAULT)
    
    As you can see in above example, part_1 has multiple entries for 4 while
    creating the partition, but describe shows only one entry for 4 in values
    set.
    Similarly, part_default has multiple entries for 3 and DEFAULT while
    creating
    the partition, but the describe shows a weired output. Instead, we should
    have
    just one entry saying "VALUES IN (DEFAULT, 3)":
    
    postgres=# \d+ part_default;
                                   Table "public.part_default"
     Column |  Type   | Collation | Nullable | Default | Storage | Stats target
    | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
     a      | integer |           |          |         | plain   |
     |
    Partition of: list_partitioned FOR VALUES IN (DEFAULT, 3)
    
    8.
    Following call to find_inheritance_children() in
    generate_qual_for_defaultpart()
    is an overhead, instead we can simply use an array of oids in rd_partdesc.
    
    + spec = (PartitionBoundSpec *) bound;
    +
    + inhoids = find_inheritance_children(RelationGetRelid(parent), NoLock);
    +
    + foreach(cell2, inhoids)
    
    Same is for the call in get_qual_from_partbound:
    
    + /* Collect bound spec nodes in a list. This is done if the partition is
    + * a default partition. In case of default partition, constraint is formed
    + * by performing <> operation over the partition constraints of the
    + * existing partitions.
    + */
    + inhoids = find_inheritance_children(RelationGetRelid(parent), NoLock);
    + foreach(cell2, inhoids)
    
    9.
    How about rephrasing following error message:
    postgres=# CREATE TABLE part_2 PARTITION OF list_partitioned FOR VALUES IN
    (14);
    ERROR:  new default partition constraint is violated by some row
    
    To,
    "ERROR: some existing row in default partition violates new default
    partition constraint"
    
    10.
    Additionally, I did test your given sample test in first post and the one
    mentioned by Keith; both of them are passing without errors.
    Also, I did a pg_dump test and it is dumping the partitions and data
    correctly.
    But as mentioned earlier, it would be good if you have them in your patch.
    
    I will do further review and let you know comments if any.
    
    Regards,
    Jeevan Ladhe
    
    On Mon, Apr 24, 2017 at 5:44 PM, Ashutosh Bapat <
    ashutosh.bapat@enterprisedb.com> wrote:
    
    > On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    > > On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > >> Following can also be considered as it specifies more clearly that the
    > >> partition holds default values.
    > >>
    > >> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    > >
    > > Yes, that could be done.  But I don't think it's correct to say that
    > > the partition holds default values.  Let's back up and ask what the
    > > word "default" means.  The relevant definition (according to Google or
    > > whoever they stole it from) is:
    > >
    > > a preselected option adopted by a computer program or other mechanism
    > > when no alternative is specified by the user or programmer.
    > >
    > > So, a default *value* is the value that is used when no alternative is
    > > specified by the user or programmer. We have that concept, but it's
    > > not what we're talking about here: that's configured by applying the
    > > DEFAULT property to a column.  Here, we're talking about the default
    > > *partition*, or in other words the *partition* that is used when no
    > > alternative is specified by the user or programmer.  So, that's why I
    > > proposed the syntax I did.  The partition doesn't contain default
    > > values; it is itself a default.
    >
    > Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more
    > natural.
    >
    >
    >
    > --
    > Best Wishes,
    > Ashutosh Bapat
    > EnterpriseDB Corporation
    > The Postgres Database Company
    >
    >
    > --
    > Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
    > To make changes to your subscription:
    > http://www.postgresql.org/mailpref/pgsql-hackers
    >
    
  45. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-04-24T18:39:14Z

    On Mon, Apr 24, 2017 at 5:44 PM, Ashutosh Bapat <
    ashutosh.bapat@enterprisedb.com> wrote:
    
    > On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    > > On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > >> Following can also be considered as it specifies more clearly that the
    > >> partition holds default values.
    > >>
    > >> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    > >
    > > Yes, that could be done.  But I don't think it's correct to say that
    > > the partition holds default values.  Let's back up and ask what the
    > > word "default" means.  The relevant definition (according to Google or
    > > whoever they stole it from) is:
    > >
    > > a preselected option adopted by a computer program or other mechanism
    > > when no alternative is specified by the user or programmer.
    > >
    > > So, a default *value* is the value that is used when no alternative is
    > > specified by the user or programmer. We have that concept, but it's
    > > not what we're talking about here: that's configured by applying the
    > > DEFAULT property to a column.  Here, we're talking about the default
    > > *partition*, or in other words the *partition* that is used when no
    > > alternative is specified by the user or programmer.  So, that's why I
    > > proposed the syntax I did.  The partition doesn't contain default
    > > values; it is itself a default.
    >
    > Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more
    > natural.
    >
    
    +1
    
  46. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-24T20:16:36Z

    On Mon, Apr 24, 2017 at 8:14 AM, Ashutosh Bapat
    <ashutosh.bapat@enterprisedb.com> wrote:
    > On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    >> On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>> Following can also be considered as it specifies more clearly that the
    >>> partition holds default values.
    >>>
    >>> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    >>
    >> The partition doesn't contain default values; it is itself a default.
    >
    > Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more natural.
    
    I suspect it could be done as of now, but I'm a little worried that it
    might create grammar conflicts in the future as we extend the syntax
    further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    word DEFAULT appears in the same position where we'd normally have FOR
    VALUES, and so the parser will definitely be able to figure out what's
    going on.  When it gets to that position, it will see FOR or it will
    see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    DEFAULT PARTITION OF ..., then we have action at a distance: whether
    or not the word DEFAULT is present before PARTITION affects which
    tokens are legal after the parent table name.  bison isn't always very
    smart about that kind of thing.  No particular dangers come to mind at
    the moment, but it makes me nervous anyway.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  47. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-25T00:29:50Z

    On 2017/04/25 5:16, Robert Haas wrote:
    > On Mon, Apr 24, 2017 at 8:14 AM, Ashutosh Bapat
    > <ashutosh.bapat@enterprisedb.com> wrote:
    >> On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    >>> On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>>> Following can also be considered as it specifies more clearly that the
    >>>> partition holds default values.
    >>>>
    >>>> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    >>>
    >>> The partition doesn't contain default values; it is itself a default.
    >>
    >> Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more natural.
    > 
    > I suspect it could be done as of now, but I'm a little worried that it
    > might create grammar conflicts in the future as we extend the syntax
    > further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    > word DEFAULT appears in the same position where we'd normally have FOR
    > VALUES, and so the parser will definitely be able to figure out what's
    > going on.  When it gets to that position, it will see FOR or it will
    > see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    > DEFAULT PARTITION OF ..., then we have action at a distance: whether
    > or not the word DEFAULT is present before PARTITION affects which
    > tokens are legal after the parent table name.  bison isn't always very
    > smart about that kind of thing.  No particular dangers come to mind at
    > the moment, but it makes me nervous anyway.
    
    +1 to CREATE TABLE .. PARTITION OF .. DEFAULT
    
    Thanks,
    Amit
    
    
    
    
  48. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-04-25T05:20:26Z

    On Tue, Apr 25, 2017 at 1:46 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    > On Mon, Apr 24, 2017 at 8:14 AM, Ashutosh Bapat
    > <ashutosh.bapat@enterprisedb.com> wrote:
    >> On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    >>> On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>>> Following can also be considered as it specifies more clearly that the
    >>>> partition holds default values.
    >>>>
    >>>> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    >>>
    >>> The partition doesn't contain default values; it is itself a default.
    >>
    >> Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more natural.
    >
    > I suspect it could be done as of now, but I'm a little worried that it
    > might create grammar conflicts in the future as we extend the syntax
    > further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    > word DEFAULT appears in the same position where we'd normally have FOR
    > VALUES, and so the parser will definitely be able to figure out what's
    > going on.  When it gets to that position, it will see FOR or it will
    > see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    > DEFAULT PARTITION OF ..., then we have action at a distance: whether
    > or not the word DEFAULT is present before PARTITION affects which
    > tokens are legal after the parent table name.
    
    As long as we handle this at the transformation stage, it shouldn't be
    a problem. The grammar would be something like
    CREATE TABLE ... optDefault PARTITION OF ...
    
    If user specifies DEFAULT PARTITION OF t1 FOR VALUES ..., parser will
    allow that but in transformation stage, we will detect it and throw an
    error "DEFAULT partitions can not contains partition bound clause" or
    something like that. Also, documentation would say that DEFAULT and
    partition bound specification are not allowed together.
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  49. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-04-25T06:03:42Z

    On 2017/04/25 14:20, Ashutosh Bapat wrote:
    > On Tue, Apr 25, 2017 at 1:46 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    >> On Mon, Apr 24, 2017 at 8:14 AM, Ashutosh Bapat
    >> <ashutosh.bapat@enterprisedb.com> wrote:
    >>> On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    >>>> On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>>>> Following can also be considered as it specifies more clearly that the
    >>>>> partition holds default values.
    >>>>>
    >>>>> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    >>>>
    >>>> The partition doesn't contain default values; it is itself a default.
    >>>
    >>> Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more natural.
    >>
    >> I suspect it could be done as of now, but I'm a little worried that it
    >> might create grammar conflicts in the future as we extend the syntax
    >> further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    >> word DEFAULT appears in the same position where we'd normally have FOR
    >> VALUES, and so the parser will definitely be able to figure out what's
    >> going on.  When it gets to that position, it will see FOR or it will
    >> see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    >> DEFAULT PARTITION OF ..., then we have action at a distance: whether
    >> or not the word DEFAULT is present before PARTITION affects which
    >> tokens are legal after the parent table name.
    > 
    > As long as we handle this at the transformation stage, it shouldn't be
    > a problem. The grammar would be something like
    > CREATE TABLE ... optDefault PARTITION OF ...
    > 
    > If user specifies DEFAULT PARTITION OF t1 FOR VALUES ..., parser will
    > allow that but in transformation stage, we will detect it and throw an
    > error "DEFAULT partitions can not contains partition bound clause" or
    > something like that. Also, documentation would say that DEFAULT and
    > partition bound specification are not allowed together.
    
    FWIW, one point to like about PARTITION OF .. DEFAULT is that it wouldn't
    need us to do things you mention we could do.  A point to not like it may
    be that it might read backwards to some users, but then the DEFAULT
    PARTITION OF have all those possibilities of error-causing user input.
    
    Thanks,
    Amit
    
    
    
    
  50. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-25T17:53:50Z

    On Tue, Apr 25, 2017 at 1:20 AM, Ashutosh Bapat
    <ashutosh.bapat@enterprisedb.com> wrote:
    >> I suspect it could be done as of now, but I'm a little worried that it
    >> might create grammar conflicts in the future as we extend the syntax
    >> further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    >> word DEFAULT appears in the same position where we'd normally have FOR
    >> VALUES, and so the parser will definitely be able to figure out what's
    >> going on.  When it gets to that position, it will see FOR or it will
    >> see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    >> DEFAULT PARTITION OF ..., then we have action at a distance: whether
    >> or not the word DEFAULT is present before PARTITION affects which
    >> tokens are legal after the parent table name.
    >
    > As long as we handle this at the transformation stage, it shouldn't be
    > a problem. The grammar would be something like
    > CREATE TABLE ... optDefault PARTITION OF ...
    >
    > If user specifies DEFAULT PARTITION OF t1 FOR VALUES ..., parser will
    > allow that but in transformation stage, we will detect it and throw an
    > error "DEFAULT partitions can not contains partition bound clause" or
    > something like that. Also, documentation would say that DEFAULT and
    > partition bound specification are not allowed together.
    
    That's not what I'm concerned about.  I'm concerned about future
    syntax additions resulting in difficult-to-resolve grammar conflicts.
    For an example what of what I mean, consider this example:
    
    http://postgr.es/m/9253.1295031520@sss.pgh.pa.us
    
    The whole thread is worth a read.  In brief, I wanted to add syntax
    like LOCK VIEW xyz, and it wasn't possible to do that without breaking
    backward compatibility.  In a nutshell, the problem with making that
    syntax work was that LOCK VIEW NOWAIT would then potentially mean
    either lock a table called VIEW with the NOWAIT option, or else it
    might mean lock a view called NOWAIT.  If the NOWAIT key word were not
    allowed at the end or if the TABLE keyword were mandatory, then it
    would be possible to make it work, but because we already decided both
    to make the TABLE keyword optional and allow an optional NOWAIT
    keyword at the end, the syntax couldn't be further extended in the way
    that I wanted to extend it without confusing the parser.  The problem
    was basically unfixable without breaking backward compatibility, and
    we gave up.  I don't want to make the same mistake with the default
    partition syntax that we made with the LOCK TABLE syntax.
    
    Aside from unfixable grammar conflicts, there's another way that this
    kind of syntax can become problematic, which is when you end up with
    multiple optional keywords in the same part of the syntax.  For an
    example of that, see
    http://postgr.es/m/603c8f070905231747j2e099c23hef8eafbf26682e5f@mail.gmail.com
    - that discusses the problems with EXPLAIN; we later ran into the same
    problem with VACUUM.  Users can't remember whether they are supposed
    to type VACUUM FULL VERBOSE or VACUUM VERBOSE FULL and trying to
    support both creates parser problems and tends to involve adding too
    many keywords, so we switched to a new and more extensible syntax for
    future options.
    
    Now, you may think that that's never going to happen in this case.
    What optional keyword other than DEFAULT could we possibly want to add
    just before PARTITION OF?  TBH, I don't know.  I can't think of
    anything else we might want to put in that position right now.  But
    considering that it's been less than six months since the original
    syntax was committed and we've already thought of ONE thing we might
    want to put there, it seems hard to rule out the possibility that we
    might eventually think of more, and then we will have exactly the same
    kind of problem that we've had in the past with other commands.  Let's
    head the problem off at the pass and pick a syntax which isn't
    vulnerable to that sort of issue.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  51. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-04-26T05:09:40Z

    On Tue, Apr 25, 2017 at 11:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    > On Tue, Apr 25, 2017 at 1:20 AM, Ashutosh Bapat
    > <ashutosh.bapat@enterprisedb.com> wrote:
    >>> I suspect it could be done as of now, but I'm a little worried that it
    >>> might create grammar conflicts in the future as we extend the syntax
    >>> further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    >>> word DEFAULT appears in the same position where we'd normally have FOR
    >>> VALUES, and so the parser will definitely be able to figure out what's
    >>> going on.  When it gets to that position, it will see FOR or it will
    >>> see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    >>> DEFAULT PARTITION OF ..., then we have action at a distance: whether
    >>> or not the word DEFAULT is present before PARTITION affects which
    >>> tokens are legal after the parent table name.
    >>
    >> As long as we handle this at the transformation stage, it shouldn't be
    >> a problem. The grammar would be something like
    >> CREATE TABLE ... optDefault PARTITION OF ...
    >>
    >> If user specifies DEFAULT PARTITION OF t1 FOR VALUES ..., parser will
    >> allow that but in transformation stage, we will detect it and throw an
    >> error "DEFAULT partitions can not contains partition bound clause" or
    >> something like that. Also, documentation would say that DEFAULT and
    >> partition bound specification are not allowed together.
    >
    > That's not what I'm concerned about.  I'm concerned about future
    > syntax additions resulting in difficult-to-resolve grammar conflicts.
    > For an example what of what I mean, consider this example:
    >
    > http://postgr.es/m/9253.1295031520@sss.pgh.pa.us
    >
    > The whole thread is worth a read.  In brief, I wanted to add syntax
    > like LOCK VIEW xyz, and it wasn't possible to do that without breaking
    > backward compatibility.  In a nutshell, the problem with making that
    > syntax work was that LOCK VIEW NOWAIT would then potentially mean
    > either lock a table called VIEW with the NOWAIT option, or else it
    > might mean lock a view called NOWAIT.  If the NOWAIT key word were not
    > allowed at the end or if the TABLE keyword were mandatory, then it
    > would be possible to make it work, but because we already decided both
    > to make the TABLE keyword optional and allow an optional NOWAIT
    > keyword at the end, the syntax couldn't be further extended in the way
    > that I wanted to extend it without confusing the parser.  The problem
    > was basically unfixable without breaking backward compatibility, and
    > we gave up.  I don't want to make the same mistake with the default
    > partition syntax that we made with the LOCK TABLE syntax.
    >
    > Aside from unfixable grammar conflicts, there's another way that this
    > kind of syntax can become problematic, which is when you end up with
    > multiple optional keywords in the same part of the syntax.  For an
    > example of that, see
    > http://postgr.es/m/603c8f070905231747j2e099c23hef8eafbf26682e5f@mail.gmail.com
    > - that discusses the problems with EXPLAIN; we later ran into the same
    > problem with VACUUM.  Users can't remember whether they are supposed
    > to type VACUUM FULL VERBOSE or VACUUM VERBOSE FULL and trying to
    > support both creates parser problems and tends to involve adding too
    > many keywords, so we switched to a new and more extensible syntax for
    > future options.
    >
    
    Thanks for taking out time for detailed explanation.
    
    > Now, you may think that that's never going to happen in this case.
    > What optional keyword other than DEFAULT could we possibly want to add
    > just before PARTITION OF?
    
    Since the grammar before PARTITION OF is shared with CREATE TABLE ()
    there is high chance that we will have an optional keyword unrelated
    to partitioning there. I take back my proposal for that syntax.
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  52. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-26T13:42:49Z

    Hello Jeevan,
    
    Thank you for comments.
    
    I will include your comments in the updated patch.
    
    >7.The output of describe needs to be improved.
    
    The syntax for DEFAULT partitioning is still under discussion. This comment
    wont be
    applicable if the syntax is changed.
    
    >6.
    >I am wondering, isn't it possible to retrieve the has_default and
    default_index
    >here to find out if default partition exists and if exist then find it's
    oid
    >using rd_partdesc, that would avoid above(7) loop to check if partition
    bound is
    >default
    The checks are used to find the default partition bound and
    exclude it from the list of partition bounds to form the partition
    constraint.
    This cant be accomplished by using has_default flag.
    isDefaultPartitionBound() is written to accomplish that.
    
    
    >8.
    >Following call to find_inheritance_children() in
    generate_qual_for_defaultpart()
    >is an overhead, instead we can simply use an array of oids in rd_partdesc.
    I think using find_inheritance_children() will take into consideration
    concurrent
    drop of a partition which the value in rd_partdesc will not.
    
    Thank you,
    Rahila Syed
    
  53. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-27T12:49:44Z

    >I suspect it could be done as of now, but I'm a little worried that it
    >might create grammar conflicts in the future as we extend the syntax
    >further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    >word DEFAULT appears in the same position where we'd normally have FOR
    >VALUES, and so the parser will definitely be able to figure out what's
    >going on.  When it gets to that position, it will see FOR or it will
    >see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    >DEFAULT PARTITION OF ..., then we have action at a distance: whether
    >or not the word DEFAULT is present before PARTITION affects which
    >tokens are legal after the parent table name.  bison isn't always very
    >smart about that kind of thing.  No particular dangers come to mind at
    >the moment, but it makes me nervous anyway.
    
    +1 for CREATE TABLE..PARTITION OF...DEFAULT  syntax.
    I think substituting DEFAULT for FOR VALUES is appropriate as
    both cases are mutually exclusive.
    
    One more thing that needs consideration is should default partitions be
    partitioned further? Other databases allow default partitions to be
    partitioned further. I think, its normal for users to expect the data in
    default partitions to also be divided into sub partitions.  So
    it should be supported.
    My colleague Rajkumar Raghuwanshi brought to my notice the current patch
    does not handle this correctly.
    I will include this in the updated patch if there is no objection.
    
    On the other hand if sub partitions of a default partition is to be
    prohibited,
    an error should be thrown if PARTITION BY is specified after DEFAULT.
    
    
    Thank you,
    Rahila Syed
    
    
    
    On Tue, Apr 25, 2017 at 1:46 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Mon, Apr 24, 2017 at 8:14 AM, Ashutosh Bapat
    > <ashutosh.bapat@enterprisedb.com> wrote:
    > > On Mon, Apr 24, 2017 at 4:24 PM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    > >> On Mon, Apr 24, 2017 at 5:10 AM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > >>> Following can also be considered as it specifies more clearly that the
    > >>> partition holds default values.
    > >>>
    > >>> CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    > >>
    > >> The partition doesn't contain default values; it is itself a default.
    > >
    > > Is CREATE TABLE ... DEFAULT PARTITION OF ... feasible? That sounds more
    > natural.
    >
    > I suspect it could be done as of now, but I'm a little worried that it
    > might create grammar conflicts in the future as we extend the syntax
    > further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    > word DEFAULT appears in the same position where we'd normally have FOR
    > VALUES, and so the parser will definitely be able to figure out what's
    > going on.  When it gets to that position, it will see FOR or it will
    > see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    > DEFAULT PARTITION OF ..., then we have action at a distance: whether
    > or not the word DEFAULT is present before PARTITION affects which
    > tokens are legal after the parent table name.  bison isn't always very
    > smart about that kind of thing.  No particular dangers come to mind at
    > the moment, but it makes me nervous anyway.
    >
    > --
    > Robert Haas
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  54. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-27T13:07:26Z

    On Thu, Apr 27, 2017 at 8:49 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >>I suspect it could be done as of now, but I'm a little worried that it
    >>might create grammar conflicts in the future as we extend the syntax
    >>further.  If we use CREATE TABLE ... PARTITION OF .. DEFAULT, then the
    >>word DEFAULT appears in the same position where we'd normally have FOR
    >>VALUES, and so the parser will definitely be able to figure out what's
    >>going on.  When it gets to that position, it will see FOR or it will
    >>see DEFAULT, and all is clear.  OTOH, if we use CREATE TABLE ...
    >>DEFAULT PARTITION OF ..., then we have action at a distance: whether
    >>or not the word DEFAULT is present before PARTITION affects which
    >>tokens are legal after the parent table name.  bison isn't always very
    >>smart about that kind of thing.  No particular dangers come to mind at
    >>the moment, but it makes me nervous anyway.
    >
    > +1 for CREATE TABLE..PARTITION OF...DEFAULT  syntax.
    > I think substituting DEFAULT for FOR VALUES is appropriate as
    > both cases are mutually exclusive.
    >
    > One more thing that needs consideration is should default partitions be
    > partitioned further? Other databases allow default partitions to be
    > partitioned further. I think, its normal for users to expect the data in
    > default partitions to also be divided into sub partitions.  So
    > it should be supported.
    > My colleague Rajkumar Raghuwanshi brought to my notice the current patch
    > does not handle this correctly.
    > I will include this in the updated patch if there is no objection.
    >
    > On the other hand if sub partitions of a default partition is to be
    > prohibited,
    > an error should be thrown if PARTITION BY is specified after DEFAULT.
    
    I see no reason to prohibit it.  You can further partition any other
    kind of partition, so there seems to be no reason to disallow it in
    this one case.
    
    Are you also working on extending this to work with range
    partitioning?  Because I think that would be good to do.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  55. Re: Adding support for Default partition in partitioning

    Sven R. Kunze <srkunze@mail.de> — 2017-04-27T19:15:30Z

    On 27.04.2017 15:07, Robert Haas wrote:
    > On Thu, Apr 27, 2017 at 8:49 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >> +1 for CREATE TABLE..PARTITION OF...DEFAULT syntax.
    >> I think substituting DEFAULT for FOR VALUES is appropriate as
    >> both cases are mutually exclusive.
    
    Just to make sound a little rounder:
    
    CREATE TABLE ... PARTITION OF ... AS DEFAULT
    CREATE TABLE ... PARTITION OF ... AS FALLBACK
    
    or
    
    CREATE TABLE ... PARTITION OF ... AS DEFAULT PARTITION
    CREATE TABLE ... PARTITION OF ... AS FALLBACK PARTITION
    
    
    Could any of these be feasible?
    
    
    Sven
    
    
    
  56. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-04-27T19:41:21Z

    Hi,
    
    On Apr 27, 2017 18:37, "Robert Haas" <robertmhaas@gmail.com> wrote:
    
    >
    >
    > Are you also working on extending this to work with range
    > partitioning?  Because I think that would be good to do.
    >
    >
    > Currently I am working on review comments and bug fixes for the
    default list partitioning patch. After that I can start with default
    partition for range partitioning.
    
    Thank you,
    Rahila Syed
    
  57. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-04-27T20:21:05Z

    On Thu, Apr 27, 2017 at 3:15 PM, Sven R. Kunze <srkunze@mail.de> wrote:
    > On 27.04.2017 15:07, Robert Haas wrote:
    >> On Thu, Apr 27, 2017 at 8:49 AM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >>>
    >>> +1 for CREATE TABLE..PARTITION OF...DEFAULT syntax.
    >>> I think substituting DEFAULT for FOR VALUES is appropriate as
    >>> both cases are mutually exclusive.
    >
    > Just to make sound a little rounder:
    >
    > CREATE TABLE ... PARTITION OF ... AS DEFAULT
    > CREATE TABLE ... PARTITION OF ... AS FALLBACK
    >
    > or
    >
    > CREATE TABLE ... PARTITION OF ... AS DEFAULT PARTITION
    > CREATE TABLE ... PARTITION OF ... AS FALLBACK PARTITION
    >
    > Could any of these be feasible?
    
    FALLBACK wouldn't be a good choice because it's not an existing parser
    keyword.  We could probably insert AS before DEFAULT and/or PARTITION
    afterwards, but they sort of seem like noise words.  SQL seems to have
    been invented by people who didn't have any trouble remembering really
    long command strings, but brevity is not without some merit.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  58. Re: Adding support for Default partition in partitioning

    Sven R. Kunze <srkunze@mail.de> — 2017-04-30T19:27:02Z

    On 27.04.2017 22:21, Robert Haas wrote:
    > On Thu, Apr 27, 2017 at 3:15 PM, Sven R. Kunze <srkunze@mail.de> wrote:
    >> Just to make sound a little rounder:
    >>
    >> CREATE TABLE ... PARTITION OF ... AS DEFAULT
    >> CREATE TABLE ... PARTITION OF ... AS FALLBACK
    >>
    >> or
    >>
    >> CREATE TABLE ... PARTITION OF ... AS DEFAULT PARTITION
    >> CREATE TABLE ... PARTITION OF ... AS FALLBACK PARTITION
    >>
    >> Could any of these be feasible?
    > FALLBACK wouldn't be a good choice because it's not an existing parser
    > keyword.  We could probably insert AS before DEFAULT and/or PARTITION
    > afterwards, but they sort of seem like noise words.
    
    You are right. I just thought it would make this variant more acceptable 
    as people expressed concerns about understandability of the command.
    
    > SQL seems to have
    > been invented by people who didn't have any trouble remembering really
    > long command strings, but brevity is not without some merit.
    
    For me, it's exactly the thing I like about SQL. It makes for an easy 
    learning curve.
    
    
    Sven
    
  59. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-05-02T16:03:03Z

    Please find attached updated patch with review comments by Robert and
    Jeevan implemented.
    
    The newly proposed syntax
    CREATE TABLE .. PARTITION OF .. DEFAULT has got most votes on this thread.
    
    If there is no more objection, I will go ahead and include that in the
    patch.
    
    Thank you,
    Rahila Syed
    
    On Mon, Apr 24, 2017 at 2:40 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello,
    >
    > Thank you for reviewing.
    >
    > >But that's not a good idea for several reasons.  For one thing, you
    > >can also write FOR VALUES IN (DEFAULT, 5) or which isn't sensible.
    > >For another thing, this kind of syntax won't generalize to range
    > >partitioning, which we've talked about making this feature support.
    > >Maybe something like:
    >
    > >CREATE TABLE .. PARTITION OF .. DEFAULT;
    >
    > I agree that the syntax should be changed to also support range
    > partitioning.
    >
    > Following can also be considered as it specifies more clearly that the
    > partition holds default values.
    >
    > CREATE TABLE ...PARTITION OF...FOR VALUES DEFAULT;
    >
    > >Maybe we should introduce a dedicated node type to
    > >represent a default-specification in the parser grammar.  If not, then
    > >let's at least encapsulate the test a little better, e.g. by adding
    > >isDefaultPartitionBound() which tests not only IsA(..., DefElem) but
    > >also whether the name is DEFAULT as expected.  BTW, we typically use
    > >lower-case internally, so if we stick with this representation it
    > >should really be "default" not "DEFAULT".
    >
    > isDefaultPartitionBound() function is created in the attached patch which
    > checks for both node type and name.
    >
    > >Why abbreviate "default" to def here?  Seems pointless.
    > Corrected in the attached.
    >
    > >Consider &&
    > Fixed.
    >
    > >+     * default partiton for rows satisfying the new partition
    > >Spelling.
    > Fixed.
    >
    > >Missing apostrophe
    > Fixed.
    >
    > >Definitely not safe against concurrency, since AccessShareLock won't
    > >exclude somebody else's update.  In fact, it won't even cover somebody
    > >else's already-in-flight transaction
    > Changed it to AccessExclusiveLock
    >
    > >Normally in such cases we try to give more detail using
    > >ExecBuildSlotValueDescription.
    > This function is used in execMain.c and the error is being
    > reported in partition.c.
    > Do you mean the error reporting should be moved into execMain.c
    > to use ExecBuildSlotValueDescription?
    >
    > >This variable starts out true and is never set to any value other than
    > >true.  Just get rid of it and, in the one place where it is currently
    > >used, write "true".  That's shorter and clearer.
    > Fixed.
    >
    > >There's not really a reason to cast the result of stringToNode() to
    > >Node * and then turn around and cast it to PartitionBoundSpec *.  Just
    > >cast it directly to whatever it needs to be.  And use the new castNode
    > >macro
    > Fixed. castNode macro takes as input Node * whereas stringToNode() takes
    > string.
    > IIUC, castNode cant be used here.
    >
    > >The if (def_elem) test continues
    > >early, but if the point is that the loop using cell3 shouldn't execute
    > >in that case, why not just put if (!def_elem) { foreach(cell3, ...) {
    > >... } } instead of reiterating the ReleaseSysCache in two places?
    > Fixed in the attached.
    >
    > I will respond to further comments in following email.
    >
    >
    > On Thu, Apr 13, 2017 at 12:48 AM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    >
    >> On Thu, Apr 6, 2017 at 7:30 AM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >> > Thanks a lot for testing and reporting this. Please find attached an
    >> updated
    >> > patch with the fix. The patch also contains a fix
    >> > regarding operator used at the time of creating expression as default
    >> > partition constraint. This was notified offlist by Amit Langote.
    >>
    >> I think that the syntax for this patch should probably be revised.
    >> Right now the proposal is for:
    >>
    >> CREATE TABLE .. PARTITION OF ... FOR VALUES IN (DEFAULT);
    >>
    >> But that's not a good idea for several reasons.  For one thing, you
    >> can also write FOR VALUES IN (DEFAULT, 5) or which isn't sensible.
    >> For another thing, this kind of syntax won't generalize to range
    >> partitioning, which we've talked about making this feature support.
    >> Maybe something like:
    >>
    >> CREATE TABLE .. PARTITION OF .. DEFAULT;
    >>
    >> This patch makes the assumption throughout that any DefElem represents
    >> the word DEFAULT, which is true in the patch as written but doesn't
    >> seem very future-proof.  I think the "def" in "DefElem" stands for
    >> "definition" or "define" or something like that, so this is actually
    >> pretty confusing.  Maybe we should introduce a dedicated node type to
    >> represent a default-specification in the parser grammar.  If not, then
    >> let's at least encapsulate the test a little better, e.g. by adding
    >> isDefaultPartitionBound() which tests not only IsA(..., DefElem) but
    >> also whether the name is DEFAULT as expected.  BTW, we typically use
    >> lower-case internally, so if we stick with this representation it
    >> should really be "default" not "DEFAULT".
    >>
    >> Useless hunk:
    >>
    >> +    bool        has_def;        /* Is there a default partition?
    >> Currently false
    >> +                                 * for a range partitioned table */
    >> +    int            def_index;        /* Index of the default list
    >> partition. -1 for
    >> +                                 * range partitioned tables */
    >>
    >> Why abbreviate "default" to def here?  Seems pointless.
    >>
    >> +                    if (found_def)
    >> +                    {
    >> +                        if (mapping[def_index] == -1)
    >> +                            mapping[def_index] = next_index++;
    >> +                    }
    >>
    >> Consider &&
    >>
    >> @@ -717,7 +754,6 @@ check_new_partition_bound(char *relname, Relation
    >> parent, Node *bound)
    >>                          }
    >>                      }
    >>                  }
    >> -
    >>                  break;
    >>              }
    >>
    >> +     * default partiton for rows satisfying the new partition
    >>
    >> Spelling.
    >>
    >> +     * constraint. If found dont allow addition of a new partition.
    >>
    >> Missing apostrophe.
    >>
    >> +        defrel = heap_open(defid, AccessShareLock);
    >> +        tupdesc = CreateTupleDescCopy(RelationGetDescr(defrel));
    >> +
    >> +        /* Build expression execution states for partition check quals */
    >> +        partqualstate = ExecPrepareCheck(partConstraint,
    >> +                        estate);
    >> +
    >> +        econtext = GetPerTupleExprContext(estate);
    >> +        snapshot = RegisterSnapshot(GetLatestSnapshot());
    >>
    >> Definitely not safe against concurrency, since AccessShareLock won't
    >> exclude somebody else's update.  In fact, it won't even cover somebody
    >> else's already-in-flight transaction.
    >>
    >> +                errmsg("new default partition constraint is violated
    >> by some row")));
    >>
    >> Normally in such cases we try to give more detail using
    >> ExecBuildSlotValueDescription.
    >>
    >> +    bool        is_def = true;
    >>
    >> This variable starts out true and is never set to any value other than
    >> true.  Just get rid of it and, in the one place where it is currently
    >> used, write "true".  That's shorter and clearer.
    >>
    >> +    inhoids = find_inheritance_children(RelationGetRelid(parent),
    >> NoLock);
    >>
    >> If it's actually safe to do this with no lock, there ought to be a
    >> comment with a very compelling explanation of why it's safe.
    >>
    >> +        boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
    >> +        bspec = (PartitionBoundSpec *)boundspec;
    >>
    >> There's not really a reason to cast the result of stringToNode() to
    >> Node * and then turn around and cast it to PartitionBoundSpec *.  Just
    >> cast it directly to whatever it needs to be.  And use the new castNode
    >> macro.
    >>
    >> +        foreach(cell1, bspec->listdatums)
    >> +        {
    >> +            Node *value = lfirst(cell1);
    >> +            if (IsA(value, DefElem))
    >> +            {
    >> +                def_elem = true;
    >> +                *defid = inhrelid;
    >> +            }
    >> +        }
    >> +        if (def_elem)
    >> +        {
    >> +            ReleaseSysCache(tuple);
    >> +            continue;
    >> +        }
    >> +        foreach(cell3, bspec->listdatums)
    >> +        {
    >> +            Node *value = lfirst(cell3);
    >> +            boundspecs = lappend(boundspecs, value);
    >> +        }
    >> +        ReleaseSysCache(tuple);
    >> +    }
    >> +    foreach(cell4, spec->listdatums)
    >> +    {
    >> +        Node *value = lfirst(cell4);
    >> +        boundspecs = lappend(boundspecs, value);
    >> +    }
    >>
    >> cell1, cell2, cell3, and cell4 are not very clear variable names.
    >> Between that and the lack of comments, this is not easy to understand.
    >> It's sort of spaghetti logic, too.  The if (def_elem) test continues
    >> early, but if the point is that the loop using cell3 shouldn't execute
    >> in that case, why not just put if (!def_elem) { foreach(cell3, ...) {
    >> ... } } instead of reiterating the ReleaseSysCache in two places?
    >>
    >> +                /* Collect bound spec nodes in a list. This is done
    >> if the partition is
    >> +                 * a default partition. In case of default partition,
    >> constraint is formed
    >> +                 * by performing <> operation over the partition
    >> constraints of the
    >> +                 * existing partitions.
    >> +                 */
    >>
    >> I doubt that handles NULLs properly.
    >>
    >> +                inhoids =
    >> find_inheritance_children(RelationGetRelid(parent), NoLock);
    >>
    >> Again, no lock?  Really?
    >>
    >> The logic which follows looks largely cut-and-pasted, which makes me
    >> think you need to do some refactoring here to make it more clear
    >> what's going on, so that you have the relevant logic in just one
    >> place.  It seems wrong anyway to shove all of this logic specific to
    >> the default case into get_qual_from_partbound() when the logic for the
    >> non-default case is inside get_qual_for_list.  Where there were 2
    >> lines of code before you've now got something like 30.
    >>
    >> +        if(get_negator(operoid) == InvalidOid)
    >> +            elog(ERROR, "no negator found for partition operator %u",
    >> +                 operoid);
    >>
    >> I really doubt that's OK.  elog() shouldn't be reachable, but this
    >> will be reachable if the partitioning operator does not have a
    >> negator.  And there's the NULL-handling issue I mentioned above, too.
    >>
    >> +            if (partdesc->boundinfo->has_def && key->strategy
    >> +                == PARTITION_STRATEGY_LIST)
    >> +                result = parent->indexes[partdesc->boun
    >> dinfo->def_index];
    >>
    >> Testing for PARTITION_STRATEGY_LIST here seems unnecessary.  If
    >> has_def (or has_default, as it probably should be) isn't allowed for
    >> range partitions, then it's redundant; if it is allowed, then that
    >> case should be handled too.  Also, at this point we've already set
    >> *failed_at and *failed_slot; presumably you'd want to make this check
    >> before you get to that point.
    >>
    >> I suspect there are quite a few more problems here in addition to the
    >> ones mentioned above, but I don't think it makes sense to spend too
    >> much time searching for them until some of this basic stuff is cleaned
    >> up.
    >>
    >> --
    >> Robert Haas
    >> EnterpriseDB: http://www.enterprisedb.com
    >> The Enterprise PostgreSQL Company
    >>
    >
    >
    
  60. Re: Adding support for Default partition in partitioning

    Amul Sul <sulamul@gmail.com> — 2017-05-04T10:32:32Z

    On Tue, May 2, 2017 at 9:33 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    > Please find attached updated patch with review comments by Robert and Jeevan
    > implemented.
    >
    Patch v8 got clean apply on latest head but server got crash at data
    insert in the following test:
    
    -- Create test table
    CREATE TABLE test ( a int, b date) PARTITION BY LIST (a);
    CREATE TABLE p1 PARTITION OF test FOR VALUES IN  (DEFAULT) PARTITION BY LIST(b);
    CREATE TABLE p11 PARTITION OF p1 FOR VALUES IN (DEFAULT);
    
    -- crash
    INSERT INTO test VALUES (210,'1/1/2002');
    
    Regards,
    Amul
    
    
    
  61. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-05-04T11:44:02Z

    Hello Amul,
    
    Thanks for reporting. Please find attached an updated patch which fixes the
    above.
    Also, the attached patch includes changes in syntax proposed upthread.
    
    The syntax implemented in this patch is as follows,
    
    CREATE TABLE p11 PARTITION OF p1 DEFAULT;
    
    Thank you,
    Rahila Syed
    
    On Thu, May 4, 2017 at 4:02 PM, amul sul <sulamul@gmail.com> wrote:
    
    > On Tue, May 2, 2017 at 9:33 PM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    > > Please find attached updated patch with review comments by Robert and
    > Jeevan
    > > implemented.
    > >
    > Patch v8 got clean apply on latest head but server got crash at data
    > insert in the following test:
    >
    > -- Create test table
    > CREATE TABLE test ( a int, b date) PARTITION BY LIST (a);
    > CREATE TABLE p1 PARTITION OF test FOR VALUES IN  (DEFAULT) PARTITION BY
    > LIST(b);
    > CREATE TABLE p11 PARTITION OF p1 FOR VALUES IN (DEFAULT);
    >
    > -- crash
    > INSERT INTO test VALUES (210,'1/1/2002');
    >
    > Regards,
    > Amul
    >
    
  62. Re: Adding support for Default partition in partitioning

    Rajkumar Raghuwanshi <rajkumar.raghuwanshi@enterprisedb.com> — 2017-05-04T12:39:28Z

    On Thu, May 4, 2017 at 5:14 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > The syntax implemented in this patch is as follows,
    >
    > CREATE TABLE p11 PARTITION OF p1 DEFAULT;
    >
    > Applied v9 patches, table description still showing old pattern of default
    partition. Is it expected?
    
    create table lpd (a int, b int, c varchar) partition by list(a);
    create table lpd_d partition of lpd DEFAULT;
    
    \d+ lpd
                                             Table "public.lpd"
     Column |       Type        | Collation | Nullable | Default | Storage  |
    Stats target | Description
    --------+-------------------+-----------+----------+---------+----------+--------------+-------------
     a      | integer           |           |          |         | plain
    |              |
     b      | integer           |           |          |         | plain
    |              |
     c      | character varying |           |          |         | extended
    |              |
    Partition key: LIST (a)
    Partitions: lpd_d FOR VALUES IN (DEFAULT)
    
  63. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-04T20:00:40Z

    Hi Rahila,
    
    I have started reviewing your latest patch, and here are my initial
    comments:
    
    1.
    In following block, we can just do with def_index, and we do not need
    found_def
    flag. We can check if def_index is -1 or not to decide if default partition
    is
    present.
    
    @@ -166,6 +172,8 @@ RelationBuildPartitionDesc(Relation rel)
      /* List partitioning specific */
      PartitionListValue **all_values = NULL;
      bool found_null = false;
    + bool found_def = false;
    + int def_index = -1;
      int null_index = -1;
    
    2.
    In check_new_partition_bound, in case of PARTITION_STRATEGY_LIST, remove
    following duplicate declaration of boundinfo, because it is confusing and
    after
    your changes it is not needed as its not getting overridden in the if block
    locally.
    if (partdesc->nparts > 0)
    {
    PartitionBoundInfo boundinfo = partdesc->boundinfo;
    ListCell   *cell;
    
    
    3.
    In following function isDefaultPartitionBound, first statement "return
    false"
    is not needed.
    
    + * Returns true if the partition bound is default
    + */
    +bool
    +isDefaultPartitionBound(Node *value)
    +{
    + if (IsA(value, DefElem))
    + {
    + DefElem *defvalue = (DefElem *) value;
    + if(!strcmp(defvalue->defname, "DEFAULT"))
    + return true;
    + return false;
    + }
    + return false;
    +}
    
    4.
    As mentioned in my previous set of comments, following if block inside a
    loop
    in get_qual_for_default needs a break:
    
    + foreach(cell1, bspec->listdatums)
    + {
    + Node *value = lfirst(cell1);
    + if (isDefaultPartitionBound(value))
    + {
    + def_elem = true;
    + *defid  = inhrelid;
    + }
    + }
    
    5.
    In the grammar the rule default_part_list is not needed:
    
    +default_partition:
    + DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1); }
    +
    +default_part_list:
    + default_partition { $$ = list_make1($1); }
    + ;
    +
    
    Instead you can simply declare default_partition as a list and write it as:
    
    default_partition:
    DEFAULT
    {
    Node *def = (Node *)makeDefElem("DEFAULT", NULL, @1);
    $$ = list_make1(def);
    }
    
    6.
    You need to change the output of the describe command, which is currently
    as below: postgres=# \d+ test; Table "public.test" Column | Type |
    Collation | Nullable | Default | Storage | Stats target | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
    a | integer | | | | plain | | b | date | | | | plain | | Partition key:
    LIST (a) Partitions: pd FOR VALUES IN (DEFAULT), test_p1 FOR VALUES IN (4,
    5) What about changing the Paritions output as below: Partitions: *pd
    DEFAULT,* test_p1 FOR VALUES IN (4, 5)
    
    7.
    You need to handle tab completion for DEFAULT.
    e.g.
    If I partially type following command:
    CREATE TABLE pd PARTITION OF test DEFA
    and then press tab, I get following completion:
    CREATE TABLE pd PARTITION OF test FOR VALUES
    
    I did some primary testing and did not find any problem so far.
    
    I will review and test further and let you know my comments.
    
    Regards,
    Jeevan Ladhe
    
    On Thu, May 4, 2017 at 6:09 PM, Rajkumar Raghuwanshi <
    rajkumar.raghuwanshi@enterprisedb.com> wrote:
    
    > On Thu, May 4, 2017 at 5:14 PM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    >
    >> The syntax implemented in this patch is as follows,
    >>
    >> CREATE TABLE p11 PARTITION OF p1 DEFAULT;
    >>
    >> Applied v9 patches, table description still showing old pattern of
    > default partition. Is it expected?
    >
    > create table lpd (a int, b int, c varchar) partition by list(a);
    > create table lpd_d partition of lpd DEFAULT;
    >
    > \d+ lpd
    >                                          Table "public.lpd"
    >  Column |       Type        | Collation | Nullable | Default | Storage  |
    > Stats target | Description
    > --------+-------------------+-----------+----------+--------
    > -+----------+--------------+-------------
    >  a      | integer           |           |          |         | plain
    > |              |
    >  b      | integer           |           |          |         | plain
    > |              |
    >  c      | character varying |           |          |         | extended
    > |              |
    > Partition key: LIST (a)
    > Partitions: lpd_d FOR VALUES IN (DEFAULT)
    >
    
  64. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-04T20:28:19Z

    While reviewing the code I was trying to explore more cases, and I here
    comes an
    open question to my mind:
    should we allow the default partition table to be partitioned further?
    
    If we allow it(as in the current case) then observe following case, where I
    have defined a default partitioned which is further partitioned on a
    different
    column.
    
    postgres=# CREATE TABLE test ( a int, b int, c int) PARTITION BY LIST (a);
    CREATE TABLE
    postgres=# CREATE TABLE test_p1 PARTITION OF test FOR VALUES IN(4, 5, 6, 7,
    8);
    CREATE TABLE
    postgres=# CREATE TABLE test_pd PARTITION OF test DEFAULT PARTITION BY
    LIST(b);
    CREATE TABLE
    postgres=# INSERT INTO test VALUES (20, 24, 12);
    ERROR:  no partition of relation "test_pd" found for row
    DETAIL:  Partition key of the failing row contains (b) = (24).
    
    Note, that it does not allow inserting the tuple(20, 24, 12) because though
    a=20
    would fall in default partition i.e. test_pd, table test_pd itself is
    further
    partitioned and does not have any partition satisfying b=24.
    Further if I define a default partition for table test_pd, the the tuple
    gets inserted.
    
    Doesn't this sound like the whole purpose of having DEFAULT partition on
    test
    table is defeated?
    
    Any views?
    
    Regards,
    Jeevan Ladhe
    
  65. Re: Adding support for Default partition in partitioning

    Sven R. Kunze <srkunze@mail.de> — 2017-05-04T20:40:17Z

    Hi Rahila,
    
    still thinking about the syntax (sorry):
    
    
    On 04.05.2017 13:44, Rahila Syed wrote:
    > [...] The syntax implemented in this patch is as follows,
    >
    > CREATE TABLE p11 PARTITION OF p1 DEFAULT;
    
    Rewriting the following:
    
    > On Thu, May 4, 2017 at 4:02 PM, amul sul <sulamul@gmail.com 
    > <mailto:sulamul@gmail.com>> wrote:
    >
    >     [...] CREATE TABLE p1 PARTITION OF test FOR VALUES IN  (DEFAULT)
    >     PARTITION BY LIST(b); [...]
    >
    
    It yields
    
    CREATE TABLE p1 PARTITION OF test DEFAULT PARTITION BY LIST(b);
    
    This reads to me like "DEFAULT PARTITION".
    
    
    I can imagine a lot of confusion when those queries are encountered in 
    the wild. I know this thread is about creating a default partition but I 
    were to propose a minor change in the following direction, I think 
    confusion would be greatly avoided:
    
    CREATE TABLE p1 PARTITION OF test*AS *DEFAULT PARTITION*ED* BY LIST(b);
    
    I know it's a bit longer but I think those 4 characters might serve 
    readability in the long term. It was especially confusing to see 
    PARTITION in two positions serving two different functions.
    
    Sven
    
  66. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-05-08T16:26:21Z

    On Thu, May 4, 2017 at 4:28 PM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > While reviewing the code I was trying to explore more cases, and I here
    > comes an
    > open question to my mind:
    > should we allow the default partition table to be partitioned further?
    
    I think yes.  In general, you are allowed to partition a partition,
    and I can't see any justification for restricting that for default
    partitions when we allow it everywhere else.
    
    > If we allow it(as in the current case) then observe following case, where I
    > have defined a default partitioned which is further partitioned on a
    > different
    > column.
    >
    > postgres=# CREATE TABLE test ( a int, b int, c int) PARTITION BY LIST (a);
    > CREATE TABLE
    > postgres=# CREATE TABLE test_p1 PARTITION OF test FOR VALUES IN(4, 5, 6, 7,
    > 8);
    > CREATE TABLE
    > postgres=# CREATE TABLE test_pd PARTITION OF test DEFAULT PARTITION BY
    > LIST(b);
    > CREATE TABLE
    > postgres=# INSERT INTO test VALUES (20, 24, 12);
    > ERROR:  no partition of relation "test_pd" found for row
    > DETAIL:  Partition key of the failing row contains (b) = (24).
    >
    > Note, that it does not allow inserting the tuple(20, 24, 12) because though
    > a=20
    > would fall in default partition i.e. test_pd, table test_pd itself is
    > further
    > partitioned and does not have any partition satisfying b=24.
    
    Right, that looks like correct behavior.  You would have gotten the
    same result if you had tried to insert into test_pd directly.
    
    > Further if I define a default partition for table test_pd, the the tuple
    > gets inserted.
    
    That also sounds correct.
    
    > Doesn't this sound like the whole purpose of having DEFAULT partition on
    > test
    > table is defeated?
    
    Not to me.  It's possible to do lots of silly things with partitioned
    tables.  For example, one case that we talked about before is that you
    can define a range partition for, say, VALUES (0) TO (100), and then
    subpartition it and give the subpartitions bounds which are outside
    the range 0-100.  That's obviously silly and will lead to failures
    inserting tuples, but we chose not to try to prohibit it because it's
    not really broken, just useless.  There are lots of similar cases
    involving other features.  For example, you can apply an inherited
    CHECK (false) constraint to a table, which makes it impossible for
    that table or any of its children to ever contain any rows; that is
    probably a dumb configuration.  You can create two unique indexes with
    exactly the same definition; unless you're creating a new one with the
    intent of dropping the old one, that doesn't make sense.  You can
    define a trigger that always throws an ERROR and then another trigger
    which runs later that modifies the tuple; the second will never be run
    because the first one will always kill the transaction before we get
    there.  Those things are all legal, but often unuseful.  Similarly
    here.  Defining a default list partition and then subpartitioning it
    by list is not likely to be a good schema design, but it doesn't mean
    we should try to disallow it.  It is important to distinguish between
    things that are actually *broken* (like a partitioning configuration
    where the tuples that can be inserted into a partition manually differ
    from the ones that are routed to it automatically) and things that are
    merely *lame* (like creating a multi-level partitioning hierarchy when
    a single level would have done the job just as well).  The former
    should be prevented by the code, while the latter is at most a
    documentation issue.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  67. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-08T18:47:39Z

    Hi Robert,
    
    Thanks for your explnation.
    
    On Mon, May 8, 2017 at 9:56 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Thu, May 4, 2017 at 4:28 PM, Jeevan Ladhe
    > <jeevan.ladhe@enterprisedb.com> wrote:
    > > While reviewing the code I was trying to explore more cases, and I here
    > > comes an
    > > open question to my mind:
    > > should we allow the default partition table to be partitioned further?
    >
    > I think yes.  In general, you are allowed to partition a partition,
    > and I can't see any justification for restricting that for default
    > partitions when we allow it everywhere else.
    >
    > > If we allow it(as in the current case) then observe following case,
    > where I
    > > have defined a default partitioned which is further partitioned on a
    > > different
    > > column.
    > >
    > > postgres=# CREATE TABLE test ( a int, b int, c int) PARTITION BY LIST
    > (a);
    > > CREATE TABLE
    > > postgres=# CREATE TABLE test_p1 PARTITION OF test FOR VALUES IN(4, 5, 6,
    > 7,
    > > 8);
    > > CREATE TABLE
    > > postgres=# CREATE TABLE test_pd PARTITION OF test DEFAULT PARTITION BY
    > > LIST(b);
    > > CREATE TABLE
    > > postgres=# INSERT INTO test VALUES (20, 24, 12);
    > > ERROR:  no partition of relation "test_pd" found for row
    > > DETAIL:  Partition key of the failing row contains (b) = (24).
    > >
    > > Note, that it does not allow inserting the tuple(20, 24, 12) because
    > though
    > > a=20
    > > would fall in default partition i.e. test_pd, table test_pd itself is
    > > further
    > > partitioned and does not have any partition satisfying b=24.
    >
    > Right, that looks like correct behavior.  You would have gotten the
    > same result if you had tried to insert into test_pd directly.
    >
    > > Further if I define a default partition for table test_pd, the the tuple
    > > gets inserted.
    >
    > That also sounds correct.
    >
    > > Doesn't this sound like the whole purpose of having DEFAULT partition on
    > > test
    > > table is defeated?
    >
    > Not to me.  It's possible to do lots of silly things with partitioned
    > tables.  For example, one case that we talked about before is that you
    > can define a range partition for, say, VALUES (0) TO (100), and then
    > subpartition it and give the subpartitions bounds which are outside
    > the range 0-100.  That's obviously silly and will lead to failures
    > inserting tuples, but we chose not to try to prohibit it because it's
    > not really broken, just useless.  There are lots of similar cases
    > involving other features.  For example, you can apply an inherited
    > CHECK (false) constraint to a table, which makes it impossible for
    > that table or any of its children to ever contain any rows; that is
    > probably a dumb configuration.  You can create two unique indexes with
    > exactly the same definition; unless you're creating a new one with the
    > intent of dropping the old one, that doesn't make sense.  You can
    > define a trigger that always throws an ERROR and then another trigger
    > which runs later that modifies the tuple; the second will never be run
    > because the first one will always kill the transaction before we get
    > there.  Those things are all legal, but often unuseful.  Similarly
    > here.  Defining a default list partition and then subpartitioning it
    > by list is not likely to be a good schema design, but it doesn't mean
    > we should try to disallow it.  It is important to distinguish between
    > things that are actually *broken* (like a partitioning configuration
    > where the tuples that can be inserted into a partition manually differ
    > from the ones that are routed to it automatically) and things that are
    > merely *lame* (like creating a multi-level partitioning hierarchy when
    > a single level would have done the job just as well).  The former
    > should be prevented by the code, while the latter is at most a
    > documentation issue.
    
    
    I agree with you that it is a user perspective on how he decides to do
    partitions of already partitioned table, and also we should have a
    demarcation between things to be handled by code and things to be
    left as common-sense or ability to define a good schema.
    
    I am ok with current behavior, provided we have atleast one-lineer in
    documentation alerting the user that partitioning the default partition will
    limit the ability of routing the tuples that do not fit in any other
    partitions.
    
    Regards,
    Jeevan Ladhe
    
  68. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-05-08T19:43:30Z

    On Thu, May 4, 2017 at 4:40 PM, Sven R. Kunze <srkunze@mail.de> wrote:
    > It yields
    >
    > CREATE TABLE p1 PARTITION OF test DEFAULT PARTITION BY LIST(b);
    >
    > This reads to me like "DEFAULT PARTITION".
    >
    > I can imagine a lot of confusion when those queries are encountered in the
    > wild. I know this thread is about creating a default partition but I were to
    > propose a minor change in the following direction, I think confusion would
    > be greatly avoided:
    >
    > CREATE TABLE p1 PARTITION OF test AS DEFAULT PARTITIONED BY LIST(b);
    >
    > I know it's a bit longer but I think those 4 characters might serve
    > readability in the long term. It was especially confusing to see PARTITION
    > in two positions serving two different functions.
    
    Well, we certainly can't make that change just for default partitions.
    I mean, that would be non-orthogonal, right?  You can't say that the
    way to subpartition is to write "PARTITION BY strategy" when the table
    unpartitioned or is a non-default partition but "PARTITIONED BY
    strategy" when it is a default partition.  That would certainly not be
    a good way of confusing users less, and would probably result in a
    variety of special cases in places like ruleutils.c or pg_dump, plus
    some weasel-wording in the documentation.  We COULD do a general
    change from "CREATE TABLE table_name PARTITION BY strategy" to "CREATE
    TABLE table_name PARTITIONED BY strategy".  I don't have any
    particular arguments against that except that the current syntax is
    more like Oracle, which might count for something, and maybe the fact
    that we're a month after feature freeze.  Still, if we want to change
    that, now would be the time; but I favor leaving it alone.
    
    I don't have a big objection to adding AS.  If that's the majority
    vote, fine; if not, that's OK, too.  I can see it might be a bit more
    clear in the case you mention, but it might also just be a noise word
    that we don't really need.  There don't seem to be many uses of AS
    that would pose a risk of actual grammar conflicts here.  I can
    imagine someone wanting to use CREATE TABLE ... PARTITION BY ... AS
    SELECT ... to create and populate a partition in one command, but that
    wouldn't be a conflict because it'd have to go AFTER the partition
    specification.  In the DEFAULT case, you'd end up with something like
    
    CREATE TABLE p1 PARTITION OF test AS DEFAULT AS <query>
    
    ...which is neither great nor horrible syntax-wise and maybe not such
    a good thing to support anyway since it would have to lock the parent
    to add the partition and then keep the lock on the parent while
    populating the new child (ouch).
    
    So I guess I'm still in favor of the CREATE TABLE p1 PARTITION OF test
    DEFAULT syntax, but if it ends up being AS DEFAULT instead, I can live
    with that.
    
    Other opinions?
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  69. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-05-09T07:19:10Z

    +1 for AS DEFAULT syntax if it helps in improving readability specially in
    following case
    
    CREATE TABLE p1 PARTITION OF test AS DEFAULT PARTITION BY LIST(a);
    
    Thank you,
    Rahila Syed
    
    On Tue, May 9, 2017 at 1:13 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    
    > On Thu, May 4, 2017 at 4:40 PM, Sven R. Kunze <srkunze@mail.de> wrote:
    > > It yields
    > >
    > > CREATE TABLE p1 PARTITION OF test DEFAULT PARTITION BY LIST(b);
    > >
    > > This reads to me like "DEFAULT PARTITION".
    > >
    > > I can imagine a lot of confusion when those queries are encountered in
    > the
    > > wild. I know this thread is about creating a default partition but I
    > were to
    > > propose a minor change in the following direction, I think confusion
    > would
    > > be greatly avoided:
    > >
    > > CREATE TABLE p1 PARTITION OF test AS DEFAULT PARTITIONED BY LIST(b);
    > >
    > > I know it's a bit longer but I think those 4 characters might serve
    > > readability in the long term. It was especially confusing to see
    > PARTITION
    > > in two positions serving two different functions.
    >
    > Well, we certainly can't make that change just for default partitions.
    > I mean, that would be non-orthogonal, right?  You can't say that the
    > way to subpartition is to write "PARTITION BY strategy" when the table
    > unpartitioned or is a non-default partition but "PARTITIONED BY
    > strategy" when it is a default partition.  That would certainly not be
    > a good way of confusing users less, and would probably result in a
    > variety of special cases in places like ruleutils.c or pg_dump, plus
    > some weasel-wording in the documentation.  We COULD do a general
    > change from "CREATE TABLE table_name PARTITION BY strategy" to "CREATE
    > TABLE table_name PARTITIONED BY strategy".  I don't have any
    > particular arguments against that except that the current syntax is
    > more like Oracle, which might count for something, and maybe the fact
    > that we're a month after feature freeze.  Still, if we want to change
    > that, now would be the time; but I favor leaving it alone.
    >
    > I don't have a big objection to adding AS.  If that's the majority
    > vote, fine; if not, that's OK, too.  I can see it might be a bit more
    > clear in the case you mention, but it might also just be a noise word
    > that we don't really need.  There don't seem to be many uses of AS
    > that would pose a risk of actual grammar conflicts here.  I can
    > imagine someone wanting to use CREATE TABLE ... PARTITION BY ... AS
    > SELECT ... to create and populate a partition in one command, but that
    > wouldn't be a conflict because it'd have to go AFTER the partition
    > specification.  In the DEFAULT case, you'd end up with something like
    >
    > CREATE TABLE p1 PARTITION OF test AS DEFAULT AS <query>
    >
    > ...which is neither great nor horrible syntax-wise and maybe not such
    > a good thing to support anyway since it would have to lock the parent
    > to add the partition and then keep the lock on the parent while
    > populating the new child (ouch).
    >
    > So I guess I'm still in favor of the CREATE TABLE p1 PARTITION OF test
    > DEFAULT syntax, but if it ends up being AS DEFAULT instead, I can live
    > with that.
    >
    > Other opinions?
    >
    > --
    > Robert Haas
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  70. Re: Adding support for Default partition in partitioning

    Sven R. Kunze <srkunze@mail.de> — 2017-05-10T14:59:58Z

    On 09.05.2017 09:19, Rahila Syed wrote:
    > +1 for AS DEFAULT syntax if it helps in improving readability 
    > specially in following case
    >
    > CREATE TABLE p1 PARTITION OF test AS DEFAULT PARTITION BY LIST(a);
    >
    > Thank you,
    > Rahila Syed
    >
    > On Tue, May 9, 2017 at 1:13 AM, Robert Haas <robertmhaas@gmail.com 
    > <mailto:robertmhaas@gmail.com>> wrote:
    >
    >     On Thu, May 4, 2017 at 4:40 PM, Sven R. Kunze <srkunze@mail.de
    >     <mailto:srkunze@mail.de>> wrote:
    >     > It yields
    >     >
    >     > CREATE TABLE p1 PARTITION OF test DEFAULT PARTITION BY LIST(b);
    >     >
    >     > This reads to me like "DEFAULT PARTITION".
    >     >
    >     > I can imagine a lot of confusion when those queries are
    >     encountered in the
    >     > wild. I know this thread is about creating a default partition
    >     but I were to
    >     > propose a minor change in the following direction, I think
    >     confusion would
    >     > be greatly avoided:
    >     >
    >     > CREATE TABLE p1 PARTITION OF test AS DEFAULT PARTITIONED BY LIST(b);
    >     >
    >     > I know it's a bit longer but I think those 4 characters might serve
    >     > readability in the long term. It was especially confusing to see
    >     PARTITION
    >     > in two positions serving two different functions.
    >
    >     Well, we certainly can't make that change just for default partitions.
    >     I mean, that would be non-orthogonal, right?  You can't say that the
    >     way to subpartition is to write "PARTITION BY strategy" when the table
    >     unpartitioned or is a non-default partition but "PARTITIONED BY
    >     strategy" when it is a default partition.  That would certainly not be
    >     a good way of confusing users less, and would probably result in a
    >     variety of special cases in places like ruleutils.c or pg_dump, plus
    >     some weasel-wording in the documentation.  We COULD do a general
    >     change from "CREATE TABLE table_name PARTITION BY strategy" to "CREATE
    >     TABLE table_name PARTITIONED BY strategy".  I don't have any
    >     particular arguments against that except that the current syntax is
    >     more like Oracle, which might count for something, and maybe the fact
    >     that we're a month after feature freeze.  Still, if we want to change
    >     that, now would be the time; but I favor leaving it alone.
    >
    
    You are definitely right. Changing it here would require to change it 
    everywhere AND thus to loose syntax parity with Oracle.
    
    I am not in a position to judge this properly whether this would be a 
    huge problem. Personally, I don't have an issue with that. But don't 
    count me as most important opion on this.
    
    >
    >     So I guess I'm still in favor of the CREATE TABLE p1 PARTITION OF test
    >     DEFAULT syntax, but if it ends up being AS DEFAULT instead, I can live
    >     with that.
    >
    
    Is to make it optional an option?
    
    Sven
    
  71. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-05-10T15:59:58Z

    On Wed, May 10, 2017 at 10:59 AM, Sven R. Kunze <srkunze@mail.de> wrote:
    > You are definitely right. Changing it here would require to change it
    > everywhere AND thus to loose syntax parity with Oracle.
    
    Right.
    
    > I am not in a position to judge this properly whether this would be a huge
    > problem. Personally, I don't have an issue with that. But don't count me as
    > most important opion on this.
    
    Well, I don't think it would be a HUGE problem, but I think the fact
    that Amit chose to implement this with syntax similar to that of
    Oracle is probably not a coincidence, but rather a goal, and I think
    the readability problem that you're worrying about is really pretty
    minor.  I think most people aren't going to subpartition their default
    partition, and I think those who do will probably find the syntax
    clear enough anyway.   So I don't favor changing it.  Now, if there's
    an outcry of support for your position then I'll stand aside but I
    don't anticipate that.
    
    >> So I guess I'm still in favor of the CREATE TABLE p1 PARTITION OF test
    >> DEFAULT syntax, but if it ends up being AS DEFAULT instead, I can live
    >> with that.
    >
    > Is to make it optional an option?
    
    Optional keywords may not be the root of ALL evil, but they're pretty
    evil.  See my posting earlier on this same thread on this topic:
    
    http://postgr.es/m/CA+TgmoZGHgd3vKZvyQ1Qx3e0L3n=voxY57mz9TTncVET-aLK2A@mail.gmail.com
    
    The issues here are more or less the same.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  72. Re: Adding support for Default partition in partitioning

    Alvaro Herrera <alvherre@2ndquadrant.com> — 2017-05-10T16:12:23Z

    I'm surprised that there is so much activity in this thread.  Is this
    patch being considered for pg10?
    
    -- 
    Álvaro Herrera                https://www.2ndQuadrant.com/
    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
    
    
    
  73. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-05-10T18:10:56Z

    On Wed, May 10, 2017 at 12:12 PM, Alvaro Herrera
    <alvherre@2ndquadrant.com> wrote:
    > I'm surprised that there is so much activity in this thread.  Is this
    > patch being considered for pg10?
    
    Of course not.  Feature freeze was a month ago.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  74. Re: Adding support for Default partition in partitioning

    Sven R. Kunze <srkunze@mail.de> — 2017-05-10T20:21:42Z

    On 10.05.2017 17:59, Robert Haas wrote:
    > Well, I don't think it would be a HUGE problem, but I think the fact
    > that Amit chose to implement this with syntax similar to that of
    > Oracle is probably not a coincidence, but rather a goal, and I think
    > the readability problem that you're worrying about is really pretty
    > minor.  I think most people aren't going to subpartition their default
    > partition, and I think those who do will probably find the syntax
    > clear enough anyway.
    
    I agree here.
    
    > Optional keywords may not be the root of ALL evil, but they're pretty
    > evil.  See my posting earlier on this same thread on this topic:
    >
    > http://postgr.es/m/CA+TgmoZGHgd3vKZvyQ1Qx3e0L3n=voxY57mz9TTncVET-aLK2A@mail.gmail.com
    >
    > The issues here are more or less the same.
    
    Ah, I see. I didn't draw the conclusion from the optionality of a 
    keyword the other day but after re-reading your post, it's exactly the 
    same issue.
    Let's avoid optional keywords!
    
    Sven
    
  75. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-05-11T14:07:53Z

    Hello,
    
    Please find attached an updated patch with review comments and bugs
    reported till date implemented.
    
    >1.
    >In following block, we can just do with def_index, and we do not need
    found_def
    >flag. We can check if def_index is -1 or not to decide if default partition
    is
    >present.
    found_def is used to set boundinfo->has_default which is used at couple
    of other places to check if default partition exists. The implementation is
    similar
    to has_null.
    
    >3.
    >In following function isDefaultPartitionBound, first statement "return
    false"
    >is not needed.
    It is needed to return false if the node is not DefElem.
    
    Todo:
    Add regression tests
    Documentation
    
    Thank you,
    Rahila Syed
    
    
    
    On Fri, May 5, 2017 at 1:30 AM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com>
    wrote:
    
    > Hi Rahila,
    >
    > I have started reviewing your latest patch, and here are my initial
    > comments:
    >
    > 1.
    > In following block, we can just do with def_index, and we do not need
    > found_def
    > flag. We can check if def_index is -1 or not to decide if default
    > partition is
    > present.
    >
    > @@ -166,6 +172,8 @@ RelationBuildPartitionDesc(Relation rel)
    >   /* List partitioning specific */
    >   PartitionListValue **all_values = NULL;
    >   bool found_null = false;
    > + bool found_def = false;
    > + int def_index = -1;
    >   int null_index = -1;
    >
    > 2.
    > In check_new_partition_bound, in case of PARTITION_STRATEGY_LIST, remove
    > following duplicate declaration of boundinfo, because it is confusing and
    > after
    > your changes it is not needed as its not getting overridden in the if block
    > locally.
    > if (partdesc->nparts > 0)
    > {
    > PartitionBoundInfo boundinfo = partdesc->boundinfo;
    > ListCell   *cell;
    >
    >
    > 3.
    > In following function isDefaultPartitionBound, first statement "return
    > false"
    > is not needed.
    >
    > + * Returns true if the partition bound is default
    > + */
    > +bool
    > +isDefaultPartitionBound(Node *value)
    > +{
    > + if (IsA(value, DefElem))
    > + {
    > + DefElem *defvalue = (DefElem *) value;
    > + if(!strcmp(defvalue->defname, "DEFAULT"))
    > + return true;
    > + return false;
    > + }
    > + return false;
    > +}
    >
    > 4.
    > As mentioned in my previous set of comments, following if block inside a
    > loop
    > in get_qual_for_default needs a break:
    >
    > + foreach(cell1, bspec->listdatums)
    > + {
    > + Node *value = lfirst(cell1);
    > + if (isDefaultPartitionBound(value))
    > + {
    > + def_elem = true;
    > + *defid  = inhrelid;
    > + }
    > + }
    >
    > 5.
    > In the grammar the rule default_part_list is not needed:
    >
    > +default_partition:
    > + DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1); }
    > +
    > +default_part_list:
    > + default_partition { $$ = list_make1($1); }
    > + ;
    > +
    >
    > Instead you can simply declare default_partition as a list and write it as:
    >
    > default_partition:
    > DEFAULT
    > {
    > Node *def = (Node *)makeDefElem("DEFAULT", NULL, @1);
    > $$ = list_make1(def);
    > }
    >
    > 6.
    > You need to change the output of the describe command, which is currently
    > as below: postgres=# \d+ test; Table "public.test" Column | Type |
    > Collation | Nullable | Default | Storage | Stats target | Description
    > --------+---------+-----------+----------+---------+---------+--------------+-------------
    > a | integer | | | | plain | | b | date | | | | plain | | Partition key:
    > LIST (a) Partitions: pd FOR VALUES IN (DEFAULT), test_p1 FOR VALUES IN (4,
    > 5) What about changing the Paritions output as below: Partitions: *pd
    > DEFAULT,* test_p1 FOR VALUES IN (4, 5)
    >
    > 7.
    > You need to handle tab completion for DEFAULT.
    > e.g.
    > If I partially type following command:
    > CREATE TABLE pd PARTITION OF test DEFA
    > and then press tab, I get following completion:
    > CREATE TABLE pd PARTITION OF test FOR VALUES
    >
    > I did some primary testing and did not find any problem so far.
    >
    > I will review and test further and let you know my comments.
    >
    > Regards,
    > Jeevan Ladhe
    >
    > On Thu, May 4, 2017 at 6:09 PM, Rajkumar Raghuwanshi <
    > rajkumar.raghuwanshi@enterprisedb.com> wrote:
    >
    >> On Thu, May 4, 2017 at 5:14 PM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >>
    >>> The syntax implemented in this patch is as follows,
    >>>
    >>> CREATE TABLE p11 PARTITION OF p1 DEFAULT;
    >>>
    >>> Applied v9 patches, table description still showing old pattern of
    >> default partition. Is it expected?
    >>
    >> create table lpd (a int, b int, c varchar) partition by list(a);
    >> create table lpd_d partition of lpd DEFAULT;
    >>
    >> \d+ lpd
    >>                                          Table "public.lpd"
    >>  Column |       Type        | Collation | Nullable | Default | Storage  |
    >> Stats target | Description
    >> --------+-------------------+-----------+----------+--------
    >> -+----------+--------------+-------------
    >>  a      | integer           |           |          |         | plain
    >> |              |
    >>  b      | integer           |           |          |         | plain
    >> |              |
    >>  c      | character varying |           |          |         | extended
    >> |              |
    >> Partition key: LIST (a)
    >> Partitions: lpd_d FOR VALUES IN (DEFAULT)
    >>
    >
    >
    
  76. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-05-12T02:38:37Z

    On Thu, May 11, 2017 at 10:07 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    > Please find attached an updated patch with review comments and bugs reported
    > till date implemented.
    
    You haven't done anything about the repeated suggestion that this
    should also cover range partitioning.
    
    +            /*
    +             * If the partition is the default partition switch
    +             * back to PARTITION_STRATEGY_LIST
    +             */
    +            if (spec->strategy == PARTITION_DEFAULT)
    +                result_spec->strategy = PARTITION_STRATEGY_LIST;
    +            else
    +                ereport(ERROR,
    +                        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    +                     errmsg("invalid bound specification for a list
    partition"),
                          parser_errposition(pstate, exprLocation(bound))));
    
    This is incredibly ugly.  I don't know exactly what should be done
    about it, but I think PARTITION_DEFAULT is a bad idea and has got to
    go.  Maybe add a separate isDefault flag to PartitionBoundSpec.
    
    +            /*
    +             * Skip if it's a partitioned table.  Only RELKIND_RELATION
    +             * relations (ie, leaf partitions) need to be scanned.
    +             */
    +            if (part_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    
    What about foreign table partitions?
    
    Doesn't it strike you as a bit strange that get_qual_for_default()
    doesn't return a qual?  Functions should generally have names that
    describe what they do.
    
    +    bound_datums = list_copy(spec->listdatums);
    +
    +    boundspecs = get_qual_for_default(parent, defid);
    +
    +    foreach(cell, bound_datums)
    +    {
    +        Node *value = lfirst(cell);
    +        boundspecs = lappend(boundspecs, value);
    +    }
    
    There's an existing function that you can use to concatenate two lists
    instead of open-coding it.
    
    Also, I think that before you ask anyone to spend too much more time
    and energy reviewing this, you should really add the documentation and
    regression tests which you mentioned as a TODO.  And run the code
    through pgindent.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  77. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-12T06:11:51Z

    Hi Rahila,
    
    On Thu, May 11, 2017 at 7:37 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    >
    > >3.
    > >In following function isDefaultPartitionBound, first statement "return
    > false"
    > >is not needed.
    > It is needed to return false if the node is not DefElem.
    >
    
    Please have a look at following code:
    
    + * Returns true if the partition bound is default
    + */
    +bool
    +isDefaultPartitionBound(Node *value)
    +{
    + if (IsA(value, DefElem))
    + {
    + DefElem defvalue = (DefElem ) value;
    + if(!strcmp(defvalue->defname, "DEFAULT"))
    + return true;
    + return false;
    + }
    + return false;
    +}
    
    By first return false, I mean to say the return statement inside the
    if block "if (IsA(value, DefElem))":
    
    + if(!strcmp(defvalue->defname, "DEFAULT"))
    + return true;
    + return false;
    
    Even if this "return false" is not present, the control is anyway going to
    fall through and will return false from the outermost return statement.
    
    I leave this decision to you, but further this block could be rewritten as
    below and also can be defined as a macro:
    
    bool
    isDefaultPartitionBound(Node *value)
    {
    return (IsA(value, DefElem) &&
    !strcmp(((DefElem) value)->defname, "DEFAULT"));
    }
    
    Regards,
    Jeevan Ladhe
    
  78. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-05-12T11:03:17Z

    On Thu, May 11, 2017 at 7:37 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello,
    >
    > Please find attached an updated patch with review comments and bugs
    > reported till date implemented.
    >
    
    Hello Rahila,
    
    Tested on "efa2c18 Doc fix: scale(numeric) returns integer, not numeric."
    
    (1) With the new patch, we allow new partitions when there is overlapping
    data with default partition. The entries in default are ignored when
    running queries satisfying the new partition.
    
    DROP TABLE list1;
    CREATE TABLE list1 (
        a int,
        b int
    ) PARTITION BY LIST (a);
    CREATE TABLE list1_1 (LIKE list1);
    ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (1);
    CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    INSERT INTO list1 SELECT generate_series(1,2),1;
    -- Partition overlapping with DEF
    CREATE TABLE list1_2 PARTITION OF list1 FOR VALUES IN (2);
    INSERT INTO list1 SELECT generate_series(2,3),2;
    
    postgres=# SELECT * FROM list1 ORDER BY a,b;
     a | b
    ---+---
     1 | 1
     2 | 1
     2 | 2
     3 | 2
    (4 rows)
    
    postgres=# SELECT * FROM list1 WHERE a=2;
     a | b
    ---+---
     2 | 2
    (1 row)
    
    This ignores the a=2 entries in the DEFAULT.
    
    postgres=# SELECT * FROM list1_def;
     a | b
    ---+---
     2 | 1
     3 | 2
    (2 rows)
    
    
    (2) I get the following warning:
    
    partition.c: In function ‘check_new_partition_bound’:
    partition.c:882:15: warning: ‘boundinfo’ may be used uninitialized in this
    function [-Wmaybe-uninitialized]
       && boundinfo->has_default)
                   ^
    preproc.y:3250.2-8: warning: type clash on default action: <str> != <>
    
    
    > >1.
    > >In following block, we can just do with def_index, and we do not need
    > found_def
    > >flag. We can check if def_index is -1 or not to decide if default
    > partition is
    > >present.
    > found_def is used to set boundinfo->has_default which is used at couple
    > of other places to check if default partition exists. The implementation
    > is similar
    > to has_null.
    >
    > >3.
    > >In following function isDefaultPartitionBound, first statement "return
    > false"
    > >is not needed.
    > It is needed to return false if the node is not DefElem.
    >
    > Todo:
    > Add regression tests
    > Documentation
    >
    > Thank you,
    > Rahila Syed
    >
    >
    >
    
  79. Re: Adding support for Default partition in partitioning

    Rahila Syed <rahilasyed90@gmail.com> — 2017-05-12T12:00:17Z

    Hello,
    
    >(1) With the new patch, we allow new partitions when there is overlapping
    data with default partition. The entries in default are ignored when
    running queries satisfying the new partition.
    This was introduced in latest version. We are not allowing adding a
    partition when entries with same key value exist in default partition. So
    this scenario should not
    come in picture. Please find attached an updated patch which corrects this.
    
    >(2) I get the following warning:
    
    >partition.c: In function ‘check_new_partition_bound’:
    >partition.c:882:15: warning: ‘boundinfo’ may be used uninitialized in this
    function [-Wmaybe-uninitialized]
    >   && boundinfo->has_default)
                   ^
    >preproc.y:3250.2-8: warning: type clash on default action: <str> != <>
    I failed to notice this warning. I will look into it.
    
    >This is incredibly ugly.  I don't know exactly what should be done
    >about it, but I think PARTITION_DEFAULT is a bad idea and has got to
    >go.  Maybe add a separate isDefault flag to PartitionBoundSpec
    Will look at other ways to do it.
    
    >Doesn't it strike you as a bit strange that get_qual_for_default()
    >doesn't return a qual?  Functions should generally have names that
    >describe what they do.
    Will fix this.
    
    >There's an existing function that you can use to concatenate two lists
    >instead of open-coding it.
    Will check this.
    
    >you should really add the documentation and
    >regression tests which you mentioned as a TODO.  And run the code
    >through pgindent
    I will also update the next version with documentation and regression tests
    and run pgindent
    
    Thank you,
    Rahila Syed
    
    On Fri, May 12, 2017 at 4:33 PM, Beena Emerson <memissemerson@gmail.com>
    wrote:
    
    >
    >
    > On Thu, May 11, 2017 at 7:37 PM, Rahila Syed <rahilasyed90@gmail.com>
    > wrote:
    >
    >> Hello,
    >>
    >> Please find attached an updated patch with review comments and bugs
    >> reported till date implemented.
    >>
    >
    > Hello Rahila,
    >
    > Tested on "efa2c18 Doc fix: scale(numeric) returns integer, not numeric."
    >
    > (1) With the new patch, we allow new partitions when there is overlapping
    > data with default partition. The entries in default are ignored when
    > running queries satisfying the new partition.
    >
    > DROP TABLE list1;
    > CREATE TABLE list1 (
    >     a int,
    >     b int
    > ) PARTITION BY LIST (a);
    > CREATE TABLE list1_1 (LIKE list1);
    > ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (1);
    > CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    > INSERT INTO list1 SELECT generate_series(1,2),1;
    > -- Partition overlapping with DEF
    > CREATE TABLE list1_2 PARTITION OF list1 FOR VALUES IN (2);
    > INSERT INTO list1 SELECT generate_series(2,3),2;
    >
    > postgres=# SELECT * FROM list1 ORDER BY a,b;
    >  a | b
    > ---+---
    >  1 | 1
    >  2 | 1
    >  2 | 2
    >  3 | 2
    > (4 rows)
    >
    > postgres=# SELECT * FROM list1 WHERE a=2;
    >  a | b
    > ---+---
    >  2 | 2
    > (1 row)
    >
    > This ignores the a=2 entries in the DEFAULT.
    >
    > postgres=# SELECT * FROM list1_def;
    >  a | b
    > ---+---
    >  2 | 1
    >  3 | 2
    > (2 rows)
    >
    >
    > (2) I get the following warning:
    >
    > partition.c: In function ‘check_new_partition_bound’:
    > partition.c:882:15: warning: ‘boundinfo’ may be used uninitialized in this
    > function [-Wmaybe-uninitialized]
    >    && boundinfo->has_default)
    >                ^
    > preproc.y:3250.2-8: warning: type clash on default action: <str> != <>
    >
    >
    >> >1.
    >> >In following block, we can just do with def_index, and we do not need
    >> found_def
    >> >flag. We can check if def_index is -1 or not to decide if default
    >> partition is
    >> >present.
    >> found_def is used to set boundinfo->has_default which is used at couple
    >> of other places to check if default partition exists. The implementation
    >> is similar
    >> to has_null.
    >>
    >> >3.
    >> >In following function isDefaultPartitionBound, first statement "return
    >> false"
    >> >is not needed.
    >> It is needed to return false if the node is not DefElem.
    >>
    >> Todo:
    >> Add regression tests
    >> Documentation
    >>
    >> Thank you,
    >> Rahila Syed
    >>
    >>
    >>
    
  80. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-05-12T14:04:57Z

    Hello,
    
    
    On Fri, May 12, 2017 at 5:30 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:
    
    > Hello,
    >
    > >(1) With the new patch, we allow new partitions when there is overlapping
    > data with default partition. The entries in default are ignored when
    > running queries satisfying the new partition.
    > This was introduced in latest version. We are not allowing adding a
    > partition when entries with same key value exist in default partition. So
    > this scenario should not
    > come in picture. Please find attached an updated patch which corrects this.
    >
    
    Thank you for the updated patch. However, now I cannot create a partition
    after default.
    
    CREATE TABLE list1 (
        a int,
        b int
    ) PARTITION BY LIST (a);
    
    CREATE TABLE list1_1 (LIKE list1);
    ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (1);
    CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    CREATE TABLE list1_5 PARTITION OF list1 FOR VALUES IN (3);
    
    server closed the connection unexpectedly
    This probably means the server terminated abnormally
    before or while processing the request.
    The connection to the server was lost. Attempting reset: Failed.
    !>
    
    
    >
    >
    > >(2) I get the following warning:
    >
    > >partition.c: In function ‘check_new_partition_bound’:
    > >partition.c:882:15: warning: ‘boundinfo’ may be used uninitialized in
    > this function [-Wmaybe-uninitialized]
    > >   && boundinfo->has_default)
    >                ^
    > >preproc.y:3250.2-8: warning: type clash on default action: <str> != <>
    > I failed to notice this warning. I will look into it.
    >
    > >This is incredibly ugly.  I don't know exactly what should be done
    > >about it, but I think PARTITION_DEFAULT is a bad idea and has got to
    > >go.  Maybe add a separate isDefault flag to PartitionBoundSpec
    > Will look at other ways to do it.
    >
    > >Doesn't it strike you as a bit strange that get_qual_for_default()
    > >doesn't return a qual?  Functions should generally have names that
    > >describe what they do.
    > Will fix this.
    >
    > >There's an existing function that you can use to concatenate two lists
    > >instead of open-coding it.
    > Will check this.
    >
    > >you should really add the documentation and
    > >regression tests which you mentioned as a TODO.  And run the code
    > >through pgindent
    > I will also update the next version with documentation and regression tests
    > and run pgindent
    >
    > Thank you,
    > Rahila Syed
    >
    > On Fri, May 12, 2017 at 4:33 PM, Beena Emerson <memissemerson@gmail.com>
    > wrote:
    >
    >>
    >>
    >> On Thu, May 11, 2017 at 7:37 PM, Rahila Syed <rahilasyed90@gmail.com>
    >> wrote:
    >>
    >>> Hello,
    >>>
    >>> Please find attached an updated patch with review comments and bugs
    >>> reported till date implemented.
    >>>
    >>
    >> Hello Rahila,
    >>
    >> Tested on "efa2c18 Doc fix: scale(numeric) returns integer, not numeric."
    >>
    >> (1) With the new patch, we allow new partitions when there is overlapping
    >> data with default partition. The entries in default are ignored when
    >> running queries satisfying the new partition.
    >>
    >> DROP TABLE list1;
    >> CREATE TABLE list1 (
    >>     a int,
    >>     b int
    >> ) PARTITION BY LIST (a);
    >> CREATE TABLE list1_1 (LIKE list1);
    >> ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (1);
    >> CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    >> INSERT INTO list1 SELECT generate_series(1,2),1;
    >> -- Partition overlapping with DEF
    >> CREATE TABLE list1_2 PARTITION OF list1 FOR VALUES IN (2);
    >> INSERT INTO list1 SELECT generate_series(2,3),2;
    >>
    >> postgres=# SELECT * FROM list1 ORDER BY a,b;
    >>  a | b
    >> ---+---
    >>  1 | 1
    >>  2 | 1
    >>  2 | 2
    >>  3 | 2
    >> (4 rows)
    >>
    >> postgres=# SELECT * FROM list1 WHERE a=2;
    >>  a | b
    >> ---+---
    >>  2 | 2
    >> (1 row)
    >>
    >> This ignores the a=2 entries in the DEFAULT.
    >>
    >> postgres=# SELECT * FROM list1_def;
    >>  a | b
    >> ---+---
    >>  2 | 1
    >>  3 | 2
    >> (2 rows)
    >>
    >>
    >> (2) I get the following warning:
    >>
    >> partition.c: In function ‘check_new_partition_bound’:
    >> partition.c:882:15: warning: ‘boundinfo’ may be used uninitialized in
    >> this function [-Wmaybe-uninitialized]
    >>    && boundinfo->has_default)
    >>                ^
    >> preproc.y:3250.2-8: warning: type clash on default action: <str> != <>
    >>
    >>
    >>> >1.
    >>> >In following block, we can just do with def_index, and we do not need
    >>> found_def
    >>> >flag. We can check if def_index is -1 or not to decide if default
    >>> partition is
    >>> >present.
    >>> found_def is used to set boundinfo->has_default which is used at couple
    >>> of other places to check if default partition exists. The implementation
    >>> is similar
    >>> to has_null.
    >>>
    >>> >3.
    >>> >In following function isDefaultPartitionBound, first statement "return
    >>> false"
    >>> >is not needed.
    >>> It is needed to return false if the node is not DefElem.
    >>>
    >>> Todo:
    >>> Add regression tests
    >>> Documentation
    >>>
    >>> Thank you,
    >>> Rahila Syed
    >>>
    >>>
    >>>
    >
    
    
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
  81. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-16T12:57:50Z

    On Fri, May 12, 2017 at 7:34 PM, Beena Emerson <memissemerson@gmail.com>
    wrote:
    
    >
    > Thank you for the updated patch. However, now I cannot create a partition
    > after default.
    >
    > CREATE TABLE list1 (
    >     a int,
    >     b int
    > ) PARTITION BY LIST (a);
    >
    > CREATE TABLE list1_1 (LIKE list1);
    > ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (1);
    > CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    > CREATE TABLE list1_5 PARTITION OF list1 FOR VALUES IN (3);
    >
    > server closed the connection unexpectedly
    > This probably means the server terminated abnormally
    > before or while processing the request.
    > The connection to the server was lost. Attempting reset: Failed.
    > !>
    >
    
    Hi,
    
    I have fixed the crash in attached patch.
    Also the patch needed bit of adjustments due to recent commit.
    I have re-based the patch on latest commit.
    
    PFA.
    
    Regards,
    Jeevan Ladhe
    
  82. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-05-16T15:31:34Z

    On Tue, May 16, 2017 at 8:57 AM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > I have fixed the crash in attached patch.
    > Also the patch needed bit of adjustments due to recent commit.
    > I have re-based the patch on latest commit.
    
    +    bool        has_default;        /* Is there a default partition?
    Currently false
    +                                 * for a range partitioned table */
    +    int            default_index;        /* Index of the default list
    partition. -1 for
    +                                 * range partitioned tables */
    
    Why do we need both has_default and default_index?  If default_index
    == -1 means that there is no default, we don't also need a separate
    bool to record the same thing, do we?
    
    get_qual_for_default() still returns a list of things that are not
    quals.  I think that this logic is all pretty poorly organized.  The
    logic to create a partitioning constraint for a list partition should
    be part of get_qual_for_list(), whether or not it is a default.  And
    when we have range partitions, the logic to create a default range
    partitioning constraint should be part of get_qual_for_range().  The
    code the way it's organized today makes it look like there are three
    kinds of partitions: list, range, and default.  But that's not right
    at all.  There are two kinds: list and range.  And a list partition
    might or might not be a default partition, and similarly for range.
    
    +                    ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION),
    +                                    errmsg("DEFAULT partition cannot be used"
    +                                           " without negator of operator  %s",
    +                                           get_opname(operoid))));
    
    I don't think ERRCODE_CHECK_VIOLATION is the right error code here,
    and we have a policy against splitting message strings like this.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  83. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-05-17T08:58:31Z

    On Tue, May 16, 2017 at 9:01 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    > On Tue, May 16, 2017 at 8:57 AM, Jeevan Ladhe
    > <jeevan.ladhe@enterprisedb.com> wrote:
    >> I have fixed the crash in attached patch.
    >> Also the patch needed bit of adjustments due to recent commit.
    >> I have re-based the patch on latest commit.
    >
    > +    bool        has_default;        /* Is there a default partition?
    > Currently false
    > +                                 * for a range partitioned table */
    > +    int            default_index;        /* Index of the default list
    > partition. -1 for
    > +                                 * range partitioned tables */
    >
    
    We have has_null and null_index for list partitioning. There
    null_index == -1 = has_null. May be Rahila and/or Jeevan just copied
    that style. Probably we should change that as well?
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  84. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-05-17T09:17:43Z

    On 2017/05/17 17:58, Ashutosh Bapat wrote:
    > On Tue, May 16, 2017 at 9:01 PM, Robert Haas <robertmhaas@gmail.com> wrote:
    >> On Tue, May 16, 2017 at 8:57 AM, Jeevan Ladhe
    >> <jeevan.ladhe@enterprisedb.com> wrote:
    >>> I have fixed the crash in attached patch.
    >>> Also the patch needed bit of adjustments due to recent commit.
    >>> I have re-based the patch on latest commit.
    >>
    >> +    bool        has_default;        /* Is there a default partition?
    >> Currently false
    >> +                                 * for a range partitioned table */
    >> +    int            default_index;        /* Index of the default list
    >> partition. -1 for
    >> +                                 * range partitioned tables */
    >>
    > 
    > We have has_null and null_index for list partitioning. There
    > null_index == -1 = has_null. May be Rahila and/or Jeevan just copied
    > that style. Probably we should change that as well?
    
    Probably a good idea.
    
    Thanks,
    Amit
    
    
    
    
  85. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-17T09:29:31Z

    On Wed, May 17, 2017 at 2:28 PM, Ashutosh Bapat <
    ashutosh.bapat@enterprisedb.com> wrote:
    
    > On Tue, May 16, 2017 at 9:01 PM, Robert Haas <robertmhaas@gmail.com>
    > wrote:
    > > On Tue, May 16, 2017 at 8:57 AM, Jeevan Ladhe
    > > <jeevan.ladhe@enterprisedb.com> wrote:
    > >> I have fixed the crash in attached patch.
    > >> Also the patch needed bit of adjustments due to recent commit.
    > >> I have re-based the patch on latest commit.
    > >
    > > +    bool        has_default;        /* Is there a default partition?
    > > Currently false
    > > +                                 * for a range partitioned table */
    > > +    int            default_index;        /* Index of the default list
    > > partition. -1 for
    > > +                                 * range partitioned tables */
    > >
    >
    > We have has_null and null_index for list partitioning. There
    > null_index == -1 = has_null. May be Rahila and/or Jeevan just copied
    > that style. Probably we should change that as well?
    >
    >
    I agree with Ashutosh.
    I had given similar comment on earlier version of patch[1]
    <https://www.postgresql.org/message-id/CAOgcT0NUUQXWRXmeVKkYTDQvWoKLYRMiPbc89ua6i_gG8FPDmA%40mail.gmail.com>,
    and  Rahila reverted
    with above reasoning, hence did not change the logic she introduced.
    
    Probably its a good idea to have a separate patch that removes has_null
    logic,
    in a separate thread.
    
    [1]
    https://www.postgresql.org/message-id/CAOgcT0NUUQXWRXmeVKkYTDQvWoKLYRMiPbc89ua6i_gG8FPDmA%40mail.gmail.com
    
    Regards,
    Jeevan Ladhe.
    
  86. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-05-22T02:01:47Z

    Hello,
    
    Patch for default range partition has been added. PFA the rebased v12 patch
    for the same.
    I have not removed the has_default variable yet.
    
    Default range partition:
    https://www.postgresql.org/message-id/CAOG9ApEYj34fWMcvBMBQ-YtqR9fTdXhdN82QEKG0SVZ6zeL1xg%40mail.gmail.com
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
  87. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-25T06:40:22Z

    Hi,
    
    I started looking into Rahila's default_partition_v11.patch, and reworked on
    few things as below:
    
    - I tried to cover all the review comments posted on the thread. Do let
    me know if something is missing.
    
    - Got rid of the functions get_qual_for_default() and
    generate_qual_for_defaultpart().
    There is no need of collecting boundspecs of all the partitions in case of
    list
    partition, the list is available in boundinfo->ndatums, an expression for
    default can be created from the information that is available in boundinfo.
    
    - Got rid of variable has_default, and added a macro for it.
    
    - Changed the logic of checking the overlapping of existing rows in default
    partition. Earlier version of patch used to build new constraints for
    default
    partition table and then was checking if any of existing rows violate those
    constraints. However, current version of patch just checks if any of the
    rows in
    default partition satisfy the new partition's constraint and fail if there
    exists any.
    This logic can also be used as it is for default partition in case of RANGE
    partitioning.
    
    - Simplified grammar rule.
    
    - Got rid of PARTITION_DEFAULT since DEFAULT is not a different partition
    strategy, the applicable logic is also revised:
    
    - There are few other code adjustments like: indentation, commenting, code
    simplification etc.
    
    - Added regression tests.
    
    TODO:
    Documentation, I am working on it. Will updated the patch soon.
    
    PFA.
    
    Regards,
    Jeevan
    
    On Mon, May 22, 2017 at 7:31 AM, Beena Emerson <memissemerson@gmail.com>
    wrote:
    
    > Hello,
    >
    > Patch for default range partition has been added. PFA the rebased v12
    > patch for the same.
    > I have not removed the has_default variable yet.
    >
    > Default range partition: https://www.postgresql.org/message-id/
    > CAOG9ApEYj34fWMcvBMBQ-YtqR9fTdXhdN82QEKG0SVZ6zeL1xg%40mail.gmail.com
    > --
    >
    > Beena Emerson
    >
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  88. Re: Adding support for Default partition in partitioning

    Rajkumar Raghuwanshi <rajkumar.raghuwanshi@enterprisedb.com> — 2017-05-25T07:09:13Z

    On Thu, May 25, 2017 at 12:10 PM, Jeevan Ladhe <
    jeevan.ladhe@enterprisedb.com> wrote:
    
    > PFA.
    >
    
    Hi
    
    I have applied v13 patch, got a crash when trying to attach default temp
    partition.
    
    postgres=# CREATE TEMP TABLE temp_list_part (a int) PARTITION BY LIST (a);
    CREATE TABLE
    postgres=# CREATE TEMP TABLE temp_def_part (a int);
    CREATE TABLE
    postgres=# ALTER TABLE temp_list_part ATTACH PARTITION temp_def_part
    DEFAULT;
    server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
    The connection to the server was lost. Attempting reset: Failed.
    !>
    
    Thanks & Regards,
    Rajkumar Raghuwanshi
    QMG, EnterpriseDB Corporation
    
  89. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-25T09:32:32Z

    Hi Rajkumar,
    
    postgres=# CREATE TEMP TABLE temp_list_part (a int) PARTITION BY LIST (a);
    > CREATE TABLE
    > postgres=# CREATE TEMP TABLE temp_def_part (a int);
    > CREATE TABLE
    > postgres=# ALTER TABLE temp_list_part ATTACH PARTITION temp_def_part
    > DEFAULT;
    > server closed the connection unexpectedly
    >     This probably means the server terminated abnormally
    >     before or while processing the request.
    > The connection to the server was lost. Attempting reset: Failed.
    > !>
    >
    
    Thanks for reporting.
    PFA patch that fixes above issue.
    
    Regards,
    Jeevan Ladhe
    
  90. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-25T09:33:05Z

    Forgot to attach the patch.
    PFA.
    
    On Thu, May 25, 2017 at 3:02 PM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com
    > wrote:
    
    > Hi Rajkumar,
    >
    > postgres=# CREATE TEMP TABLE temp_list_part (a int) PARTITION BY LIST (a);
    >> CREATE TABLE
    >> postgres=# CREATE TEMP TABLE temp_def_part (a int);
    >> CREATE TABLE
    >> postgres=# ALTER TABLE temp_list_part ATTACH PARTITION temp_def_part
    >> DEFAULT;
    >> server closed the connection unexpectedly
    >>     This probably means the server terminated abnormally
    >>     before or while processing the request.
    >> The connection to the server was lost. Attempting reset: Failed.
    >> !>
    >>
    >
    > Thanks for reporting.
    > PFA patch that fixes above issue.
    >
    > Regards,
    > Jeevan Ladhe
    >
    
  91. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-05-29T06:55:15Z

    On Thu, May 25, 2017 at 3:03 PM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    >
    > Forgot to attach the patch.
    > PFA.
    >
    > On Thu, May 25, 2017 at 3:02 PM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> wrote:
    >>
    >> Hi Rajkumar,
    >>
    >>> postgres=# CREATE TEMP TABLE temp_list_part (a int) PARTITION BY LIST (a);
    >>> CREATE TABLE
    >>> postgres=# CREATE TEMP TABLE temp_def_part (a int);
    >>> CREATE TABLE
    >>> postgres=# ALTER TABLE temp_list_part ATTACH PARTITION temp_def_part DEFAULT;
    >>> server closed the connection unexpectedly
    >>>     This probably means the server terminated abnormally
    >>>     before or while processing the request.
    >>> The connection to the server was lost. Attempting reset: Failed.
    >>> !>
    >>
    >>
    >> Thanks for reporting.
    >> PFA patch that fixes above issue.
    >>
    
    
    The existing comment is not valid
                /*
                 * A null partition key is only acceptable if null-accepting list
                 * partition exists.
                 */
    as we allow NULL to be stored in default. It should be updated.
    
    DROP TABLE list1;
    CREATE TABLE list1 (    a int) PARTITION BY LIST (a);
    CREATE TABLE list1_1 (LIKE list1);
    ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (2);
    CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    INSERT INTO list1 VALUES (NULL);
    SELECT * FROM list1_def;
     a
    ---
    
    (1 row)
    
    
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  92. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-29T08:57:04Z

    This patch needs a rebase on recent commits, and also a fix[1] that is
    posted for get_qual_for_list().
    
    I am working on both of these tasks. Will update the patch once I am done
    with this.
    
    
    Regards,
    
    Jeevan Ladhe
    
    On Mon, May 29, 2017 at 12:25 PM, Beena Emerson <memissemerson@gmail.com>
    wrote:
    
    > On Thu, May 25, 2017 at 3:03 PM, Jeevan Ladhe
    > <jeevan.ladhe@enterprisedb.com> wrote:
    > >
    > > Forgot to attach the patch.
    > > PFA.
    > >
    > > On Thu, May 25, 2017 at 3:02 PM, Jeevan Ladhe <
    > jeevan.ladhe@enterprisedb.com> wrote:
    > >>
    > >> Hi Rajkumar,
    > >>
    > >>> postgres=# CREATE TEMP TABLE temp_list_part (a int) PARTITION BY LIST
    > (a);
    > >>> CREATE TABLE
    > >>> postgres=# CREATE TEMP TABLE temp_def_part (a int);
    > >>> CREATE TABLE
    > >>> postgres=# ALTER TABLE temp_list_part ATTACH PARTITION temp_def_part
    > DEFAULT;
    > >>> server closed the connection unexpectedly
    > >>>     This probably means the server terminated abnormally
    > >>>     before or while processing the request.
    > >>> The connection to the server was lost. Attempting reset: Failed.
    > >>> !>
    > >>
    > >>
    > >> Thanks for reporting.
    > >> PFA patch that fixes above issue.
    > >>
    >
    >
    > The existing comment is not valid
    >             /*
    >              * A null partition key is only acceptable if null-accepting
    > list
    >              * partition exists.
    >              */
    > as we allow NULL to be stored in default. It should be updated.
    >
    > DROP TABLE list1;
    > CREATE TABLE list1 (    a int) PARTITION BY LIST (a);
    > CREATE TABLE list1_1 (LIKE list1);
    > ALTER TABLE  list1 ATTACH PARTITION list1_1 FOR VALUES IN (2);
    > CREATE TABLE list1_def PARTITION OF list1 DEFAULT;
    > INSERT INTO list1 VALUES (NULL);
    > SELECT * FROM list1_def;
    >  a
    > ---
    >
    > (1 row)
    >
    >
    > --
    >
    > Beena Emerson
    >
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  93. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-29T08:58:36Z

    >
    > The existing comment is not valid
    >             /*
    >              * A null partition key is only acceptable if null-accepting
    > list
    >              * partition exists.
    >              */
    > as we allow NULL to be stored in default. It should be updated.
    >
    
    Sure Beena, as stated earlier will update this on my next version of patch.
    
    
    Regards,
    Jeevan Ladhe
    
  94. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-29T16:03:45Z

    Hi,
    
    I have rebased the patch on latest commit with few cosmetic changes.
    
    The patch fix_listdatums_get_qual_for_list_v3.patch [1]
    <http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg315490.html>
     needs to be applied
    before applying this patch.
    
    [1] http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg315490.html
    
    Regards,
    Jeevan Ladhe
    
    
    On Mon, May 29, 2017 at 2:28 PM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com
    > wrote:
    
    >
    >
    >> The existing comment is not valid
    >>             /*
    >>              * A null partition key is only acceptable if null-accepting
    >> list
    >>              * partition exists.
    >>              */
    >> as we allow NULL to be stored in default. It should be updated.
    >>
    >
    > Sure Beena, as stated earlier will update this on my next version of patch.
    >
    >
    > Regards,
    > Jeevan Ladhe
    >
    
  95. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-05-30T05:29:45Z

    On Mon, May 29, 2017 at 9:33 PM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > Hi,
    >
    > I have rebased the patch on latest commit with few cosmetic changes.
    >
    > The patch fix_listdatums_get_qual_for_list_v3.patch [1]  needs to be applied
    > before applying this patch.
    >
    > [1] http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg315490.html
    >
    
    
    This needs a rebase again.
    
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  96. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-30T07:38:47Z

    Hi,
    
    I have rebased the patch on the latest commit.
    PFA.
    
    There exists one issue reported by Rajkumar[1] off-line as following, where
    describing the default partition after deleting null partition, does not
    show
    updated constraints. I am working on fixing this issue.
    
    create table t1 (c1 int) partition by list (c1);
    create table t11 partition of t1 for values in (1,2);
    create table t12 partition of t1 default;
    create table t13 partition of t1 for values in (10,11);
    create table t14 partition of t1 for values in (null);
    
    postgres=# \d+ t12
                                        Table "public.t12"
     Column |  Type   | Collation | Nullable | Default | Storage | Stats target
    | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
     c1     | integer |           |          |         | plain   |
     |
    Partition of: t1 DEFAULT
    Partition constraint: ((c1 IS NOT NULL) AND (c1 <> ALL (ARRAY[1, 2, 10,
    11])))
    
    postgres=# alter table t1 detach partition t14;
    ALTER TABLE
    postgres=# \d+ t12
                                        Table "public.t12"
     Column |  Type   | Collation | Nullable | Default | Storage | Stats target
    | Description
    --------+---------+-----------+----------+---------+---------+--------------+-------------
     c1     | integer |           |          |         | plain   |
     |
    Partition of: t1 DEFAULT
    Partition constraint: ((c1 IS NOT NULL) AND (c1 <> ALL (ARRAY[1, 2, 10,
    11])))
    
    postgres=# insert into t1 values(null);
    INSERT 0 1
    
    Note that the parent correctly allows the nulls to be inserted.
    
    [1] rajkumar.raghuwanshi@enterprisedb.com
    
    Regards,
    Jeevan Ladhe
    
    On Tue, May 30, 2017 at 10:59 AM, Beena Emerson <memissemerson@gmail.com>
    wrote:
    
    > On Mon, May 29, 2017 at 9:33 PM, Jeevan Ladhe
    > <jeevan.ladhe@enterprisedb.com> wrote:
    > > Hi,
    > >
    > > I have rebased the patch on latest commit with few cosmetic changes.
    > >
    > > The patch fix_listdatums_get_qual_for_list_v3.patch [1]  needs to be
    > applied
    > > before applying this patch.
    > >
    > > [1] http://www.mail-archive.com/pgsql-hackers@postgresql.org/
    > msg315490.html
    > >
    >
    >
    > This needs a rebase again.
    >
    > --
    >
    > Beena Emerson
    >
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  97. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-30T11:21:26Z

    Hi,
    
    I have fixed the issue related to default partition constraints not getting
    updated
    after detaching a partition.
    
    PFA.
    
    Regards,
    Jeevan Ladhe
    
    On Tue, May 30, 2017 at 1:08 PM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com
    > wrote:
    
    > Hi,
    >
    > I have rebased the patch on the latest commit.
    > PFA.
    >
    > There exists one issue reported by Rajkumar[1] off-line as following, where
    > describing the default partition after deleting null partition, does not
    > show
    > updated constraints. I am working on fixing this issue.
    >
    > create table t1 (c1 int) partition by list (c1);
    > create table t11 partition of t1 for values in (1,2);
    > create table t12 partition of t1 default;
    > create table t13 partition of t1 for values in (10,11);
    > create table t14 partition of t1 for values in (null);
    >
    > postgres=# \d+ t12
    >                                     Table "public.t12"
    >  Column |  Type   | Collation | Nullable | Default | Storage | Stats
    > target | Description
    > --------+---------+-----------+----------+---------+--------
    > -+--------------+-------------
    >  c1     | integer |           |          |         | plain   |
    >  |
    > Partition of: t1 DEFAULT
    > Partition constraint: ((c1 IS NOT NULL) AND (c1 <> ALL (ARRAY[1, 2, 10,
    > 11])))
    >
    > postgres=# alter table t1 detach partition t14;
    > ALTER TABLE
    > postgres=# \d+ t12
    >                                     Table "public.t12"
    >  Column |  Type   | Collation | Nullable | Default | Storage | Stats
    > target | Description
    > --------+---------+-----------+----------+---------+--------
    > -+--------------+-------------
    >  c1     | integer |           |          |         | plain   |
    >  |
    > Partition of: t1 DEFAULT
    > Partition constraint: ((c1 IS NOT NULL) AND (c1 <> ALL (ARRAY[1, 2, 10,
    > 11])))
    >
    > postgres=# insert into t1 values(null);
    > INSERT 0 1
    >
    > Note that the parent correctly allows the nulls to be inserted.
    >
    > [1] rajkumar.raghuwanshi@enterprisedb.com
    >
    > Regards,
    > Jeevan Ladhe
    >
    > On Tue, May 30, 2017 at 10:59 AM, Beena Emerson <memissemerson@gmail.com>
    > wrote:
    >
    >> On Mon, May 29, 2017 at 9:33 PM, Jeevan Ladhe
    >> <jeevan.ladhe@enterprisedb.com> wrote:
    >> > Hi,
    >> >
    >> > I have rebased the patch on latest commit with few cosmetic changes.
    >> >
    >> > The patch fix_listdatums_get_qual_for_list_v3.patch [1]  needs to be
    >> applied
    >> > before applying this patch.
    >> >
    >> > [1] http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg
    >> 315490.html
    >> >
    >>
    >>
    >> This needs a rebase again.
    >>
    >> --
    >>
    >> Beena Emerson
    >>
    >> EnterpriseDB: http://www.enterprisedb.com
    >> The Enterprise PostgreSQL Company
    >>
    >
    >
    
  98. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-05-30T12:41:35Z

    On Tue, May 30, 2017 at 1:08 PM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > Hi,
    >
    > I have rebased the patch on the latest commit.
    > PFA.
    >
    
    Thanks for rebasing the patch. Here are some review comments.
    +                /*
    +                 * In case of default partition, just note the index, we do not
    +                 * add this to non_null_values list.
    +                 */
    We may want to rephrase it like
    "Note the index of the partition bound spec for the default partition. There's
    no datum to add to the list of non-null datums for this partition."
    
                        /* Assign mapping index for default partition. */
    "mapping index" should be "mapped index". May be we want to use "the" before
    default partition everywhere, there's only one specific default partition.
    
                            Assert(default_index >= 0 &&
                                   mapping[default_index] == -1);
    Needs some explanation for asserting mapping[default_index] == -1. Since
    default partition accepts any non-specified value, it should not get a mapped
    index while assigning those for non-null datums.
    
    +                     * Currently range partition do not have default partition
    May be rephrased as "As of now, we do not support default range partition."
    
    +     * ArrayExpr, which would return an negated expression for default
    a negated instead of an negated.
    
    +        cur_index = -1;
             /*
    -         * A null partition key is only acceptable if null-accepting list
    -         * partition exists.
    +         * A null partition key is acceptable if null-accepting list partition
    +         * or a default partition exists. Check if there exists a null
    +         * accepting partition, else this will be handled later by default
    +         * partition if it exists.
              */
    -        cur_index = -1;
    Why do we need to move assignment to cur_index before the comment.
    The comment should probably change to "Handle NULL partition key here
    if there's a
    null-accepting list partition. Else it will routed to a default partition if
    one exists."
    
    +-- attaching default partition overlaps if a default partition already exists
    +ERROR:  partition "part_def2" would overlap partition "part_def1"
    Saying a default partition overlaps is misleading here. A default partition is
    not exepected to overlap with anything. It's expected to "adjust" with the rest
    of the partitions. It can "conflict" with another default partition. So the
    right error message here is "a default partition "part_def1" already exists."
    
    +CREATE TABLE part_def1 PARTITION OF list_parted DEFAULT;
    +CREATE TABLE part_def2 (LIKE part_1 INCLUDING CONSTRAINTS);
    +ALTER TABLE list_parted ATTACH PARTITION part_def2 DEFAULT;
    May be you want to name part_def1 as def_part and part_def2 as fail_def_part to
    be consistent with other names in the file. May be you want to test to
    consecutive CREATE TABLE ... DEFAULT.
    
    +ALTER TABLE list_parted2 ATTACH PARTITION part_3 FOR VALUES IN (11);
    +ERROR:  new default partition constraint is violated by some row
    +DETAIL:  Violating row contains (11, z).
    The error message seems to be misleading. The default partition is not new. May
    be we should say, "default partition contains rows that conflict with the
    partition bounds of "part_3"". I think we should use a better word instead of
    "conflict", but I am not able to find one right now.
    
    +-- check that leaf partitons of default partition are scanned when
    s/partitons/partitions/
    
    -ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a
    SET NOT NULL;
    -ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);
    +ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5, 55)), ALTER
    a SET NOT NULL;
    +ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5, 55);
    Why do we want to change partition bounds of this one? The test is for children
    of part_5 right?
    
    +drop table part_default;
    I think this is premature drop. Down the file there's a SELECT from
    list_parted, which won't list the rows inserted to the default partition and we
    will miss to check whether the tuples were routed to the right partition or
    not.
    
    +update list_part1 set a = 'c' where a = 'a';
    +ERROR:  new row for relation "list_part1" violates partition constraint
    +DETAIL:  Failing row contains (c, 1).
    Why do we need this test here? It's not dealing with the default partition and
    partition row movement is not in there. So the updated row may not move to the
    default partition, even if it's there.
    
    This isn't a complete review. I will continue to review this patch further.
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  99. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-05-31T00:33:45Z

    Hi Jeevan,
    
    On 2017/05/30 16:38, Jeevan Ladhe wrote:
    > I have rebased the patch on the latest commit.
    > PFA.
    
    Was looking at the patch and felt that the parse node representation of
    default partition bound could be slightly different.  Can you explain the
    motivation behind implementing it without adding a new member to the
    PartitionBoundSpec struct?
    
    I would suggest instead adding a bool named is_default and be done with
    it.  It will help get rid of the public isDefaultPartitionBound() in the
    proposed patch whose interface isn't quite clear and instead simply check
    if (spec->is_default) in places where it's called by passing it (Node *)
    linitial(spec->listdatums).
    
    Further looking into the patch, I found a tiny problem in
    check_default_allows_bound().  If the default partition that will be
    scanned by it is a foreign table or a partitioned table with a foreign
    leaf partition, you will get a failure like:
    
    -- default partition is a foreign table
    alter table p attach partition fp default;
    
    -- adding a new partition will try to scan fp above
    alter table p attach partition p12 for values in (1, 2);
    ERROR:  could not open file "base/13158/16456": No such file or directory
    
    I think the foreign tables should be ignored here to avoid the error.  The
    fact that foreign default partition may contain data that satisfies the
    new partition's constraint is something we cannot do much about.  Also,
    see the note in ATTACH PARTITION description regarding foreign tables [1]
    and the discussion at [2].
    
    Thanks,
    Amit
    
    [1] https://www.postgresql.org/docs/devel/static/sql-altertable.html
    [2]
    https://www.postgresql.org/message-id/flat/8f89dcb2-bd15-d8dc-5f54-3e11dc6c9463%40lab.ntt.co.jp
    
    
    
    
  100. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-05-31T01:28:35Z

    Thanks Amit for your comments.
    
    On 31-May-2017 6:03 AM, "Amit Langote" <Langote_Amit_f8@lab.ntt.co.jp>
    wrote:
    
    Hi Jeevan,
    
    On 2017/05/30 16:38, Jeevan Ladhe wrote:
    > I have rebased the patch on the latest commit.
    > PFA.
    
    Was looking at the patch and felt that the parse node representation of
    default partition bound could be slightly different.  Can you explain the
    motivation behind implementing it without adding a new member to the
    PartitionBoundSpec struct?
    
    I would suggest instead adding a bool named is_default and be done with
    it.  It will help get rid of the public isDefaultPartitionBound() in the
    proposed patch whose interface isn't quite clear and instead simply check
    if (spec->is_default) in places where it's called by passing it (Node *)
    linitial(spec->listdatums).
    
    
    I thought of reusing the existing members of PartitionBoundSpec, but I
    agree that having a bool could simplify the code. Will do the receptive
    change.
    
    Further looking into the patch, I found a tiny problem in
    check_default_allows_bound().  If the default partition that will be
    scanned by it is a foreign table or a partitioned table with a foreign
    leaf partition, you will get a failure like:
    
    -- default partition is a foreign table
    alter table p attach partition fp default;
    
    -- adding a new partition will try to scan fp above
    alter table p attach partition p12 for values in (1, 2);
    ERROR:  could not open file "base/13158/16456": No such file or directory
    
    I think the foreign tables should be ignored here to avoid the error.  The
    fact that foreign default partition may contain data that satisfies the
    new partition's constraint is something we cannot do much about.  Also,
    see the note in ATTACH PARTITION description regarding foreign tables [1]
    and the discussion at [2].
    
    
    Will look into this.
    
    Regards,
    Jeevan Ladhe
    
  101. Re: Adding support for Default partition in partitioning

    Amit Langote <langote_amit_f8@lab.ntt.co.jp> — 2017-05-31T02:43:20Z

    On 2017/05/31 9:33, Amit Langote wrote:
    > On 2017/05/30 16:38, Jeevan Ladhe wrote:
    >> I have rebased the patch on the latest commit.
    >> PFA.
    > 
    > Was looking at the patch
    
    I tried creating default partition of a range-partitioned table and got
    the following error:
    
    ERROR:  invalid bound specification for a range partition
    
    I thought it would give:
    
    ERROR: creating default partition is not supported for range partitioned
    tables
    
    Which means transformPartitionBound() should perform this check more
    carefully.  As I suggested in my previous email, if there were a
    is_default field in the PartitionBoundSpec, then one could add the
    following block of code at the beginning of transformPartitionBound:
    
    
      if (spec->is_default && spec->strategy != PARTITION_STRATEGY_LIST)
          ereport(ERROR,
                  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                   errmsg("creating default partition is not supported for %s
    partitioned tables", get_partition_strategy_name(key->strategy))));
    
    
    Some more comments on the patch:
    
    +                         errmsg("new default partition constraint is
    violated by some row"),
    
    "new default partition constraint" may sound a bit confusing to users.
    That we recompute the default partition's constraint and check the "new
    constraint" against the rows it contains seems to me to be the description
    of internal details.  How about:
    
    ERROR: default partition contains rows that belong to partition being created
    
    +char *ExecBuildSlotValueDescription(Oid reloid,
    +                              TupleTableSlot *slot,
    +                              TupleDesc tupdesc,
    +                              Bitmapset *modifiedCols,
    +                              int maxfieldlen);
    
    It seems that you made the above public to use it in
    check_default_allows_bound(), which while harmless, I'm not sure if
    needed.  ATRewriteTable() in tablecmds.c, for example, emits the following
    error messages:
    
    errmsg("check constraint \"%s\" is violated by some row",
    
    errmsg("partition constraint is violated by some row")));
    
    but neither outputs the DETAIL part showing exactly what row.  I think
    it's fine for check_default_allows_bound() not to show the row itself and
    hence no need to make ExecBuildSlotValueDescription public.
    
    
    In get_rule_expr():
    
                         case PARTITION_STRATEGY_LIST:
                             Assert(spec->listdatums != NIL);
    
    +                        /*
    +                         * If the boundspec is of Default partition, it does
    +                         * not have list of datums, but has only one node to
    +                         * indicate its a default partition.
    +                         */
    +                        if (isDefaultPartitionBound(
    +                                        (Node *) linitial(spec->listdatums)))
    +                        {
    +                            appendStringInfoString(buf, "DEFAULT");
    +                            break;
    +                        }
    +
    
    How about adding this part before the switch (key->strategy)?  That way,
    we won't have to come back and add this again when we add range default
    partitions.
    
    Gotta go; will provide more comments later.
    
    Thanks,
    Amit
    
    
    
    
  102. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-05-31T04:20:44Z

    On Wed, May 31, 2017 at 8:13 AM, Amit Langote
    <Langote_Amit_f8@lab.ntt.co.jp> wrote:
    > On 2017/05/31 9:33, Amit Langote wrote:
    >
    >
    > In get_rule_expr():
    >
    >                      case PARTITION_STRATEGY_LIST:
    >                          Assert(spec->listdatums != NIL);
    >
    > +                        /*
    > +                         * If the boundspec is of Default partition, it does
    > +                         * not have list of datums, but has only one node to
    > +                         * indicate its a default partition.
    > +                         */
    > +                        if (isDefaultPartitionBound(
    > +                                        (Node *) linitial(spec->listdatums)))
    > +                        {
    > +                            appendStringInfoString(buf, "DEFAULT");
    > +                            break;
    > +                        }
    > +
    >
    > How about adding this part before the switch (key->strategy)?  That way,
    > we won't have to come back and add this again when we add range default
    > partitions.
    
    I think it is best that we add a bool is_default to PartitionBoundSpec
    and then have a general check for both list and range. Though
    listdatums, upperdatums and lowerdatums are set to default for a
    DEFAULt partition, it does not seem proper that we check listdatums
    for range as well.
    
    
    
    
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  103. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-06-01T19:35:03Z

    Hi,
    
    I have addressed Ashutosh's and Amit's comments in the attached patch.
    
    Please let me know if I have missed anything and any further comments.
    
    PFA.
    
    Regards,
    Jeevan Ladhe
    
    On Wed, May 31, 2017 at 9:50 AM, Beena Emerson <memissemerson@gmail.com>
    wrote:
    
    > On Wed, May 31, 2017 at 8:13 AM, Amit Langote
    > <Langote_Amit_f8@lab.ntt.co.jp> wrote:
    > > On 2017/05/31 9:33, Amit Langote wrote:
    > >
    > >
    > > In get_rule_expr():
    > >
    > >                      case PARTITION_STRATEGY_LIST:
    > >                          Assert(spec->listdatums != NIL);
    > >
    > > +                        /*
    > > +                         * If the boundspec is of Default partition, it
    > does
    > > +                         * not have list of datums, but has only one
    > node to
    > > +                         * indicate its a default partition.
    > > +                         */
    > > +                        if (isDefaultPartitionBound(
    > > +                                        (Node *)
    > linitial(spec->listdatums)))
    > > +                        {
    > > +                            appendStringInfoString(buf, "DEFAULT");
    > > +                            break;
    > > +                        }
    > > +
    > >
    > > How about adding this part before the switch (key->strategy)?  That way,
    > > we won't have to come back and add this again when we add range default
    > > partitions.
    >
    > I think it is best that we add a bool is_default to PartitionBoundSpec
    > and then have a general check for both list and range. Though
    > listdatums, upperdatums and lowerdatums are set to default for a
    > DEFAULt partition, it does not seem proper that we check listdatums
    > for range as well.
    >
    >
    >
    >
    > --
    >
    > Beena Emerson
    >
    > EnterpriseDB: http://www.enterprisedb.com
    > The Enterprise PostgreSQL Company
    >
    
  104. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-06-02T20:41:35Z

    On Thu, Jun 1, 2017 at 3:35 PM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > Please let me know if I have missed anything and any further comments.
    
    +                     errmsg("a default partition \"%s\" already exists",
    
    I suggest: partition \"%s\" conflicts with existing default partition \"%s\"
    
    The point is that's more similar to the message you get when overlap
    && !spec->is_default.
    
    +     * If the default partition exists, it's partition constraint will change
    
    it's -> its
    
    +                         errmsg("default partition contains row(s)
    that would overlap with partition being created")));
    
    It doesn't really sound right to talk about rows overlapping with a
    partition.  Partitions can overlap with each other, but not rows.
    Also, it's not really project style to use ambiguously plural forms
    like "row(s)" in error messages.  Maybe something like:
    
    new partition constraint for default partition \"%s\" would be
    violated by some row
    
    +/*
    + * InvalidateDefaultPartitionRelcache
    + *
    + * Given a parent oid, this function checks if there exists a default partition
    + * and invalidates it's relcache if it exists.
    + */
    +void
    +InvalidateDefaultPartitionRelcache(Oid parentOid)
    +{
    +    Relation parent = heap_open(parentOid, AccessShareLock);
    +    Oid default_relid =
    parent->rd_partdesc->oids[DEFAULT_PARTITION_INDEX(parent)];
    +
    +    if (partition_bound_has_default(parent->rd_partdesc->boundinfo))
    +        CacheInvalidateRelcacheByRelid(default_relid);
    +
    +    heap_close(parent, AccessShareLock);
    +}
    
    It does not seem like a good idea to put the heap_open() call inside
    this function.  One of the two callers already *has* the Relation, and
    we definitely want to avoid pulling the Oid out of the Relation only
    to reopen it to get the Relation back.  And I think
    heap_drop_with_catalog could open the parent relation instead of
    calling LockRelationOid().
    
    If DETACH PARTITION and DROP PARTITION require this, why not ATTACH
    PARTITION and CREATE TABLE .. PARTITION OF?
    
    The indentation of the changes in gram.y doesn't appear to match the
    nearby code.  I'd remove this comment:
    
    +             * Currently this is supported only for LIST partition.
    
    Since nothing here is dependent on this working only for LIST
    partitions, and since this will probably change, I think it would be
    more future-proof to leave this out, lest somebody forget to update it
    later.
    
    -                switch (spec->strategy)
    +                if (spec->is_default && (strategy == PARTITION_STRATEGY_LIST ||
    +                                         strategy == PARTITION_STRATEGY_RANGE))
    
    Checking strategy here appears pointless.
    
    This is not a full review, but I'm out of time for today.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  105. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-06-03T11:43:18Z

    Here's some detailed review of the code.
    
    @@ -1883,6 +1883,15 @@ heap_drop_with_catalog(Oid relid)
         if (OidIsValid(parentOid))
         {
             /*
    +         * Default partition constraints are constructed run-time from the
    +         * constraints of its siblings(basically by negating them), so any
    +         * change in the siblings needs to rebuild the constraints of the
    +         * default partition. So, invalidate the sibling default partition's
    +         * relcache.
    +         */
    +        InvalidateDefaultPartitionRelcache(parentOid);
    +
    Do we need a lock on the default partition for doing this? A query might be
    scanning the default partition directly and we will invalidate the relcache
    underneath it. What if two partitions are being dropped simultaneously and
    change default constraints simultaneously. Probably the lock on the parent
    helps there, but need to check it. What if the default partition cache is
    invalidated because partition gets added/dropped to the default partition
    itself. If we need a lock on the default partition, we will need to
    check the order in which we should be obtaining the locks so as to avoid
    deadlocks. This also means that we have to test PREPARED statements involving
    default partition. Any addition/deletion/attach/detach of other partition
    should invalidate those cached statements.
    
    +                        if (partition_bound_has_default(boundinfo))
    +                        {
    +                            overlap = true;
    +                            with = boundinfo->default_index;
    +                        }
    You could possibly rewrite this as
    overlap = partition_bound_has_default(boundinfo);
    with = boundinfo->default_index;
    that would save one indentation and a conditional jump.
    
    +    if (partdesc->nparts > 0 && partition_bound_has_default(boundinfo))
    +        check_default_allows_bound(parent, spec);
    If the table has a default partition, nparts > 0, nparts > 0 check looks
    redundant. The comments above should also explain that this check doesn't
    trigger when a default partition is added since we don't expect an existing
    default partition in such a case.
    
    + * Checks if there exists any row in the default partition that passes the
    + * check for constraints of new partition, if any reports an error.
    grammar two conflicting ifs in the same statement. You may want to rephrase
    this as "This function checks if there exists a row in the default
    partition that fits in the new
    partition and throws an error if it finds one."
    
    +    if (new_spec->strategy != PARTITION_STRATEGY_LIST)
    +        return;
    This should probably be an Assert. When default range partition is supported
    this function would silently return, meaning there is no row in the default
    partition which fits the new partition. We don't want that behavior.
    
    The code in check_default_allows_bound() to check whether the default partition
    has any rows that would fit new partition looks quite similar to the code in
    ATExecAttachPartition() checking whether all rows in the table being attached
    as a partition fit the partition bounds. One thing that
    check_default_allows_bound() misses is, if there's already a constraint on the
    default partition refutes the partition constraint on the new partition, we can
    skip the scan of the default partition since it can not have rows that would
    fit the new partition. ATExecAttachPartition() has code to deal with a similar
    case i.e. the table being attached has a constraint which implies the partition
    constraint. There may be more cases which check_default_allows_bound() does not
    handle but ATExecAttachPartition() handles. So, I am wondering whether it's
    better to somehow take out the common code into a function and use it. We will
    have to deal with a difference through. The first one would throw an error when
    finding a row that satisfies partition constraints whereas the second one would
    throw an error when it doesn't find such a row. But this difference can be
    handled through a flag or by negating the constraint. This would also take care
    of Amit Langote's complaint about foreign partitions. There's also another
    difference that the ATExecAttachPartition() queues the table for scan and the
    actual scan takes place in ATRewriteTable(), but there is not such queue while
    creating a table as a partition. But we should check if we can reuse the code to
    scan the heap for checking a constraint.
    
    In case of ATTACH PARTITION, probably we should schedule scan of default
    partition in the alter table's work queue like what ATExecAttachPartition() is
    doing for the table being attached. That would fit in the way alter table
    works.
    
     make_partition_op_expr(PartitionKey key, int keynum,
    -                       uint16 strategy, Expr *arg1, Expr *arg2)
    +                    uint16 strategy, Expr *arg1, Expr *arg2, bool is_default)
    Indentation
    
    +                if (is_default &&
    +                    ((operoid = get_negator(operoid)) == InvalidOid))
    +                    ereport(ERROR, (errcode(ERRCODE_RESTRICT_VIOLATION),
    +                                    errmsg("DEFAULT partition cannot
    be used without negator of operator  %s",
    +                                           get_opname(operoid))));
    +
    If the existence of default partition depends upon the negator, shouldn't there
    be a dependency between the default partition and the negator. At the time of
    creating the default partition, we will try to constuct the partition
    constraint for the default partition and if the negator doesn't exist that
    time, it will throw an error. But in an unlikely event when the user drops the
    negator, the partitioned table will not be usable at all, as every time it will
    try to create the relcache, it will try to create default partition constraint
    and will throw error because of missing negator. That's not a very good
    scenario. Have you tried this case? Apart from that, while restoring a dump, if
    the default partition gets restored before the negator is created, restore will
    fail with this error.
    
         /* Generate the main expression, i.e., keyCol = ANY (arr) */
         opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
    -                                    keyCol, (Expr *) arr);
    +                                    keyCol, (Expr *) arr, spec->is_default);
                     /* Build leftop = ANY (rightop) */
                     saopexpr = makeNode(ScalarArrayOpExpr);
    The comments in both the places need correction, as for default partition the
    expression will be keyCol <> ALL(arr).
    
    +    /*
    +     * In case of the default partition for list, the partition constraint
    +     * is basically any value that is not equal to any of the values in
    +     * boundinfo->datums array. So, construct a list of constants from
    +     * boundinfo->datums to pass to function make_partition_op_expr via
    +     * ArrayExpr, which would return a negated expression for the default
    +     * partition.
    +     */
    This is misleading, since the actual constraint would also have NOT NULL or IS
    NULL in there depending upon the existence of a NULL partition.
    I would simply rephrase this as "For default list partition, collect lists for
    all the partitions. The default partition constraint should check that the
    partition key is equal to none of those."
    
    +        ndatums = (pdesc->nparts > 0) ? boundinfo->ndatums : 0;
    wouldn't ndatums be simply boundinfo->ndatums? When nparts = 0, ndatums will be
    0.
    +        int         ndatums = 0;
    This assignment looks redundant then.
    
    +        if (boundinfo && partition_bound_accepts_nulls(boundinfo))
    You have not checked existence of boundinfo when extracting ndatums out of it
    and just few lines below you check that. If the later check is required then we
    will get a segfault while extracting ndatums.
    
    +    if ((!list_has_null && !spec->is_default) ||
    +        (list_has_null && spec->is_default))
    Need a comment explaining what's going on here. The condition is no more a
    simple condition.
    
    -            result = -1;
    -            *failed_at = parent;
    -            *failed_slot = slot;
    -            break;
    +            if (partition_bound_has_default(partdesc->boundinfo))
    +            {
    +                result = parent->indexes[partdesc->boundinfo->default_index];
    +
    +                if (result >= 0)
    +                    break;
    +                else
    +                    parent = pd[-result];
    +            }
    +            else
    +            {
    +                result = -1;
    +                *failed_at = parent;
    +                *failed_slot = slot;
    +                break;
    +            }
    The code to handle result is duplicated here and few lines below. I think it
    would be better to not duplicate it by having separate condition blocks to deal
    with setting result and setting parent. Basically if (cur_index < 0) ... else
    would set the result breaking when setting result = -1 explicitly. A follow-on
    block would adjust the parent if result < 0 or break otherwise.
    
    Both the places where DEFAULT_PARTITION_INDEX is used, its result is used to
    fetch OID of the default partition. So, instead of having this macro, may be we
    should have macro to fetch OID of default partition. But even there I don't see
    much value in that. Further, the macro and code using that macro fetches
    rd_partdesc directly from Relation. We have RelationGetPartitionDesc() for
    that. Probably we should also add Asserts to check that every pointer in the
    long pointer chain is Non-null.
    
    InvalidateDefaultPartitionRelcache() is called in case of drop and detach.
    Shouldn't the constraint change when we add or attach a new partition.
    Shouldn't we invalidate the cache then as well? I am not able to find that
    code in your patch.
    
         /*
    +     * Default partition constraints are constructed run-time from the
    +     * constraints of its siblings(basically by negating them), so any
    +     * change in the siblings needs to rebuild the constraints of the
    +     * default partition. So, invalidate the sibling default partition's
    +     * relcache.
    +     */
    May be rephrase this as "The default partition constraints depend upon the
    partition bounds of other partitions. Detaching a partition invalidates the
    default partition constraints. Invalidate the default partition's relcache so
    that the constraints are built anew and any plans dependent on those
    constraints are invalidated as well."
    
    +                     errmsg("default partition is supported only for
    list partitioned table")));
    for "a" list partitioned table.
    
    +            /*
    +             * A default partition, that can be partition of either LIST or
    +             * RANGE partitioned table.
    +             * Currently this is supported only for LIST partition.
    +             */
    Keep everything in single paragraph without line break.
    
                     }
    +
             ;
    unnecessary extra line.
    
    +        /*
    +         * The default partition bound does not have any datums to be
    +         * transformed, return the new bound.
    +         */
    Probably not needed.
    
    +                if (spec->is_default && (strategy == PARTITION_STRATEGY_LIST ||
    +                                         strategy == PARTITION_STRATEGY_RANGE))
    +                {
    +                    appendStringInfoString(buf, "DEFAULT");
    +                    break;
    +                }
    +
    What happens if strategy is something other than RANGE or LIST. For that matter
    why not just LIST? Possibly you could write this as
    +                if (spec->is_default)
    +                {
    +                    Assert(strategy == PARTITION_STRATEGY_LIST);
    +                    appendStringInfoString(buf, "DEFAULT");
    +                    break;
    +                }
    
    @@ -2044,7 +2044,7 @@ psql_completion(const char *text, int start, int end)
             COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
         /* Limited completion support for partition bound specification */
         else if (TailMatches3("ATTACH", "PARTITION", MatchAny))
    -        COMPLETE_WITH_CONST("FOR VALUES");
    +        COMPLETE_WITH_LIST2("FOR VALUES", "DEFAULT");
         else if (TailMatches2("FOR", "VALUES"))
             COMPLETE_WITH_LIST2("FROM (", "IN (");
    
    @@ -2483,7 +2483,7 @@ psql_completion(const char *text, int start, int end)
             COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_partitioned_tables, "");
         /* Limited completion support for partition bound specification */
         else if (TailMatches3("PARTITION", "OF", MatchAny))
    -        COMPLETE_WITH_CONST("FOR VALUES");
    +        COMPLETE_WITH_LIST2("FOR VALUES", "DEFAULT");
    Do we include psql tab completion in the main feature patch? I have not seen
    this earlier. But appreciate taking care of these defails.
    
    +char *ExecBuildSlotValueDescription(Oid reloid,
    needs an "extern" declaration.
    
    On Fri, Jun 2, 2017 at 1:05 AM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > Hi,
    >
    > I have addressed Ashutosh's and Amit's comments in the attached patch.
    >
    > Please let me know if I have missed anything and any further comments.
    >
    > PFA.
    >
    > Regards,
    > Jeevan Ladhe
    >
    > On Wed, May 31, 2017 at 9:50 AM, Beena Emerson <memissemerson@gmail.com>
    > wrote:
    >>
    >> On Wed, May 31, 2017 at 8:13 AM, Amit Langote
    >> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
    >> > On 2017/05/31 9:33, Amit Langote wrote:
    >> >
    >> >
    >> > In get_rule_expr():
    >> >
    >> >                      case PARTITION_STRATEGY_LIST:
    >> >                          Assert(spec->listdatums != NIL);
    >> >
    >> > +                        /*
    >> > +                         * If the boundspec is of Default partition, it
    >> > does
    >> > +                         * not have list of datums, but has only one
    >> > node to
    >> > +                         * indicate its a default partition.
    >> > +                         */
    >> > +                        if (isDefaultPartitionBound(
    >> > +                                        (Node *)
    >> > linitial(spec->listdatums)))
    >> > +                        {
    >> > +                            appendStringInfoString(buf, "DEFAULT");
    >> > +                            break;
    >> > +                        }
    >> > +
    >> >
    >> > How about adding this part before the switch (key->strategy)?  That way,
    >> > we won't have to come back and add this again when we add range default
    >> > partitions.
    >>
    >> I think it is best that we add a bool is_default to PartitionBoundSpec
    >> and then have a general check for both list and range. Though
    >> listdatums, upperdatums and lowerdatums are set to default for a
    >> DEFAULt partition, it does not seem proper that we check listdatums
    >> for range as well.
    >>
    >>
    >>
    >>
    >> --
    >>
    >> Beena Emerson
    >>
    >> EnterpriseDB: http://www.enterprisedb.com
    >> The Enterprise PostgreSQL Company
    >
    >
    
    
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  106. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-06-04T13:00:28Z

    Hi Robert,
    
    Thanks for your comments:
    
    
    > If DETACH PARTITION and DROP PARTITION require this, why not ATTACH
    > PARTITION and CREATE TABLE .. PARTITION OF?
    >
    >
    For CREATE and ATTACH parition the invalidation of default relation is taken
    care by the following clean-up part in check_default_allows_bound():
    
    + ResetExprContext(econtext);
    + CHECK_FOR_INTERRUPTS();
    + }
    +
    + CacheInvalidateRelcache(part_rel);
    + MemoryContextSwitchTo(oldCxt);
    
    However, post your comment I carefully looked in the code I wrote here, and
    I
    see that this still explicitly needs cache invalidation in ATTACH and CREATE
    command, because the above invalidation call will not happen in case the
    default partition is further partitioned. Plus, I think the call to
    CacheInvalidateRelcache() in check_default_allows_bound() can be completely
    removed.
    
    This code however will be rearranged, as I plan to address Ashutosh's one
    of the
    comment to write a function for common code of ATExecAttachPartition() and
    check_default_allows_bound().
    
    Regards,
    Jeevan Ladhe
    
  107. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-06-04T18:36:30Z

    Hello,
    
    On Fri, Jun 2, 2017 at 1:05 AM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    > Hi,
    >
    > I have addressed Ashutosh's and Amit's comments in the attached patch.
    >
    > Please let me know if I have missed anything and any further comments.
    >
    > PFA.
    >
    > Regards,
    > Jeevan Ladhe
    >
    
    What is the reason the new patch does not mention of violating rows
    when a new partition overlaps with default?
    Is it because more than one row could be violating the condition?
    
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  108. Re: Adding support for Default partition in partitioning

    Jeevan Ladhe <jeevan.ladhe@enterprisedb.com> — 2017-06-04T18:44:20Z

    > What is the reason the new patch does not mention of violating rows
    > when a new partition overlaps with default?
    > Is it because more than one row could be violating the condition?
    >
    
    This is because, for reporting the violating error, I had to function
    ExecBuildSlotValueDescription() public. Per Amit's comment I have
    removed this change and let the overlapping error without row contains.
    I think this is analogus to other functions that are throwing violation
    error
    but are not local to execMain.c.
    
    Regards,
    Jeevan Ladhe
    
  109. Re: Adding support for Default partition in partitioning

    Beena Emerson <memissemerson@gmail.com> — 2017-06-04T18:46:31Z

    On Mon, Jun 5, 2017 at 12:14 AM, Jeevan Ladhe
    <jeevan.ladhe@enterprisedb.com> wrote:
    >
    >
    >>
    >> What is the reason the new patch does not mention of violating rows
    >> when a new partition overlaps with default?
    >> Is it because more than one row could be violating the condition?
    >
    >
    > This is because, for reporting the violating error, I had to function
    > ExecBuildSlotValueDescription() public. Per Amit's comment I have
    > removed this change and let the overlapping error without row contains.
    > I think this is analogus to other functions that are throwing violation
    > error
    > but are not local to execMain.c.
    >
    
    ok thanks.
    
    
    -- 
    
    Beena Emerson
    
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company
    
    
    
  110. Re: Adding support for Default partition in partitioning

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-06-07T09:47:28Z

    On Sat, Jun 3, 2017 at 2:11 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    >
    > +                         errmsg("default partition contains row(s)
    > that would overlap with partition being created")));
    >
    > It doesn't really sound right to talk about rows overlapping with a
    > partition.  Partitions can overlap with each other, but not rows.
    > Also, it's not really project style to use ambiguously plural forms
    > like "row(s)" in error messages.  Maybe something like:
    >
    > new partition constraint for default partition \"%s\" would be
    > violated by some row
    >
    
    Partition constraint is implementation detail here. We enforce
    partition bounds through constraints and we call such constraints as
    partition constraints. But a user may not necessarily understand this
    term or may interpret it different. Adding "new" adds to the confusion
    as the default partition is not new. My suggestion in an earlier mail
    was ""default partition contains rows that conflict with the partition
    bounds of "part_xyz"", with a note that we should use a better word
    than "conflict". So, Jeevan seems to have used overlap, which again is
    not correct. How about "default partition contains row/s which would
    fit the partition "part_xyz" being created or attached." with a hint
    to move those rows to the new partition's table in case of attach. I
    don't think hint would be so straight forward i.e. to create the table
    with SELECT INTO and then ATTACH.
    
    What do you think?
    
    Also, the error code ERRCODE_CHECK_VIOLATION, which is an "integrity
    constraint violation" code, seems misleading. We aren't violating any
    integrity here. In fact I am not able to understand, how could adding
    an object violate integrity constraint. The nearest errorcode seems to
    be ERRCODE_INVALID_OBJECT_DEFINITION, which is also used for
    partitions with overlapping bounds.
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  111. Re: Adding support for Default partition in partitioning

    Robert Haas <robertmhaas@gmail.com> — 2017-06-08T16:56:10Z

    On Wed, Jun 7, 2017 at 5:47 AM, Ashutosh Bapat
    <ashutosh.bapat@enterprisedb.com> wrote:
    > On Sat, Jun 3, 2017 at 2:11 AM, Robert Haas <robertmhaas@gmail.com> wrote:
    >>
    >> +                         errmsg("default partition contains row(s)
    >> that would overlap with partition being created")));
    >>
    >> It doesn't really sound right to talk about rows overlapping with a
    >> partition.  Partitions can overlap with each other, but not rows.
    >> Also, it's not really project style to use ambiguously plural forms
    >> like "row(s)" in error messages.  Maybe something like:
    >>
    >> new partition constraint for default partition \"%s\" would be
    >> violated by some row
    >
    > Partition constraint is implementation detail here. We enforce
    > partition bounds through constraints and we call such constraints as
    > partition constraints. But a user may not necessarily understand this
    > term or may interpret it different. Adding "new" adds to the confusion
    > as the default partition is not new.
    
    I see your point.  We could say "updated partition constraint" instead
    of "new partition constraint" to address that to some degree.
    
    > My suggestion in an earlier mail
    > was ""default partition contains rows that conflict with the partition
    > bounds of "part_xyz"", with a note that we should use a better word
    > than "conflict". So, Jeevan seems to have used overlap, which again is
    > not correct. How about "default partition contains row/s which would
    > fit the partition "part_xyz" being created or attached." with a hint
    > to move those rows to the new partition's table in case of attach. I
    > don't think hint would be so straight forward i.e. to create the table
    > with SELECT INTO and then ATTACH.
    
    The problem is that none of these actually sound very good.  Neither
    conflict nor overlap nor fit actually express the underlying idea very
    clearly, at least IMHO.  I'm not opposed to using some wording along
    these lines if we can think of a clear way to word it, but I think my
    wording is better than using some unclear word for this concept.  I
    can't immediately think of a way to adjust your wording so that it
    seems completely clear.
    
    > Also, the error code ERRCODE_CHECK_VIOLATION, which is an "integrity
    > constraint violation" code, seems misleading. We aren't violating any
    > integrity here. In fact I am not able to understand, how could adding
    > an object violate integrity constraint. The nearest errorcode seems to
    > be ERRCODE_INVALID_OBJECT_DEFINITION, which is also used for
    > partitions with overlapping bounds.
    
    I think that calling a constraint failure a check violation is not too
    much of a stretch, even if it's technically a partition constraint
    rather than a CHECK constraint.  However, your proposal also seems
    reasonable.  I'm happy to go with whatever most people like best.
    
    -- 
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise PostgreSQL Company