Thread

Commits

  1. Use generateClonedIndexStmt to propagate CREATE INDEX to partitions.

  1. BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    The Post Office <noreply@postgresql.org> — 2024-09-27T14:31:54Z

    The following bug has been logged on the website:
    
    Bug reference:      18637
    Logged by:          CREATE INDEX won&#x27;t look up operator classes in search_path if PARTITION BY
    is specified
    Email address:      usamoi@outlook.com
    PostgreSQL version: 17.0
    Operating system:   Linux 6.10
    Description:        
    
    This SQL works in PostgreSQL 16.4 but not in PostgreSQL 17.0. Here
    `vector_l2_ops` is an operator class in schema `vectors`.
    ```
    SET search_path TO public, vectors;
    CREATE TABLE items (val vector(3), category_id int) PARTITION BY
    LIST(category_id);
    CREATE TABLE id_123 PARTITION OF items FOR VALUES IN (1, 2, 3);
    CREATE TABLE id_456 PARTITION OF items FOR VALUES IN (4, 5, 6);
    CREATE TABLE id_789 PARTITION OF items FOR VALUES IN (7, 8, 9);
    CREATE INDEX ON items USING vectors (val vector_l2_ops);
    ```
    The error message is: `ERROR:  operator class "vector_l2_ops" does not exist
    for access method "vectors"`
    
    If I do not use PARTITION BY and CREATE TABLE OF, it works and the message
    is `CREATE INDEX`.
    
    After debugging, I find that `DefineIndex` would call `RestrictSearchPath`
    in `indexcmds.c:1234` and `indexcmds.c:1334` before entering recursion, so
    that the nested `DefineIndex` would be only able to look up operator classes
    in `pg_catalog, pg_temp`.
    
    Since the behavior between `CREATE INDEX` and `CREATE INDEX PARTITION BY` is
    different, it should be a bug.
    
    
  2. Re: BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    David Rowley <dgrowleyml@gmail.com> — 2024-10-03T03:11:40Z

    On Sat, 28 Sept 2024 at 02:59, PG Bug reporting form
    <noreply@postgresql.org> wrote:
    > After debugging, I find that `DefineIndex` would call `RestrictSearchPath`
    > in `indexcmds.c:1234` and `indexcmds.c:1334` before entering recursion, so
    > that the nested `DefineIndex` would be only able to look up operator classes
    > in `pg_catalog, pg_temp`.
    >
    > Since the behavior between `CREATE INDEX` and `CREATE INDEX PARTITION BY` is
    > different, it should be a bug.
    
    There's an item in the release notes [1] which should be expended to
    mention this as an incompatibility, namely:
    
    "Change functions to use a safe search_path during maintenance
    operations (Jeff Davis) §
    
    This prevents maintenance operations (ANALYZE, CLUSTER, REFRESH
    MATERIALIZED VIEW, REINDEX, or VACUUM) from performing unsafe access.
    Functions used by expression indexes and materialized views that need
    to reference non-default schemas must specify a search path during
    function creation."
    
    That doesn't quite mention CREATE INDEX. There's a discussion about
    fixing that by adding CREATE INDEX to the list of commands. See [2].
    
    I think you can now safely assume that you'll need to provide the
    schema name for the opclass you've specified.
    
    Also please see the CREATE INDEX documentation [3] where it says:
    
    "While CREATE INDEX is running, the search_path is temporarily changed
    to pg_catalog, pg_temp."
    
    David
    
    [1] https://www.postgresql.org/docs/release/17.0/
    [2] https://www.postgresql.org/message-id/20240926141921.57d0b430fa53ac4389344847%40sraoss.co.jp
    [3] https://www.postgresql.org/docs/17/sql-createindex.html
    
    
    
    
  3. Re: BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    Tom Lane <tgl@sss.pgh.pa.us> — 2024-10-03T03:19:03Z

    David Rowley <dgrowleyml@gmail.com> writes:
    > There's an item in the release notes [1] which should be expended to
    > mention this as an incompatibility, namely:
    
    > "Change functions to use a safe search_path during maintenance
    > operations (Jeff Davis) §
    
    I have not dug into the code, but I think this may actually be a
    bug; not because of the change of search path, but because it looks
    like the opclass is probably being looked up more than once during
    the command, with different search paths.  That has security
    implications, and not good ones.  We should fix this so that the
    opclass is looked up exactly once, and passed down to the partitions
    by OID not name.
    
    			regards, tom lane
    
    
    
    
  4. Re: BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    Tom Lane <tgl@sss.pgh.pa.us> — 2024-10-03T16:51:34Z

    I wrote:
    > I have not dug into the code, but I think this may actually be a
    > bug; not because of the change of search path, but because it looks
    > like the opclass is probably being looked up more than once during
    > the command, with different search paths.  That has security
    > implications, and not good ones.  We should fix this so that the
    > opclass is looked up exactly once, and passed down to the partitions
    > by OID not name.
    
    Here's an example that doesn't rely on any outside extension:
    
    regression=# create extension cube;
    CREATE EXTENSION
    regression=# create table items(category_id int, val cube) partition by list(category_id);
    CREATE TABLE
    regression=# CREATE INDEX ON items (val cube_ops);
    CREATE INDEX
    regression=# CREATE TABLE id_123 PARTITION OF items FOR VALUES IN (1, 2);
    CREATE TABLE
    regression=# CREATE INDEX items_idx_2 ON items (val cube_ops);
    ERROR:  operator class "cube_ops" does not exist for access method "btree"
    
    So that's pretty awful: creating the partitioned index by itself is
    willing to look up the opclass in the current search path, and then
    adding a new partition will play nice with that, but creating a
    partitioned index when there's already a partition will not.
    It's got to be considered a bug that the two paths for making a
    child index behave differently.
    
    As far as I understand, the change of search path is only supposed to
    affect user-defined code within the expressions of an expression index.
    Operands of the command itself should consistently be interpreted in
    the current search path.
    
    			regards, tom lane
    
    
    
    
  5. Re: BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    Tom Lane <tgl@sss.pgh.pa.us> — 2024-10-03T18:17:15Z

    I wrote:
    > So that's pretty awful: creating the partitioned index by itself is
    > willing to look up the opclass in the current search path, and then
    > adding a new partition will play nice with that, but creating a
    > partitioned index when there's already a partition will not.
    > It's got to be considered a bug that the two paths for making a
    > child index behave differently.
    
    I looked into this and found that
    
    * When adding a partition to a pre-existing partitioned index,
    we use generateClonedIndexStmt() to construct the IndexStmt
    for DefineIndex to use.  This is proof against the current
    problem because it will always schema-qualify the opclass
    name, cf. get_opclass().
    
    * However, if CREATE INDEX recurses to create a child partition,
    it does this:
    
                        IndexStmt  *childStmt = copyObject(stmt);
    
    followed by some pretty ad-hoc cleanup.  If the original
    IndexStmt wasn't written in a search-path-independent fashion
    then we've got trouble.
    
    It seems clear to me that the right fix for this is to use
    generateClonedIndexStmt in this code path too.  I am not
    claiming that generateClonedIndexStmt is entirely free of
    related issues, but to the extent it has any we'd have to
    fix them anyway.  Building the IndexStmt in two fundamentally
    different ways is just asking for trouble.
    
    I hacked this up and was amused to discover that it also
    fixes a TODO left over from c01eb619a: if there's a comment
    for the parent index, we've been incorrectly applying it
    to children too.  generateClonedIndexStmt knows better than
    to fill idxcomment for the child IndexStmt, but copyObject
    does not.
    
    This could stand an additional regression test case perhaps,
    but the core tests don't have a suitable opclass at hand.
    Maybe we could test it in some contrib module, but that
    seems a shade hacky.
    
    Thoughts?
    
    			regards, tom lane
    
    
  6. Re: BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    Noah Misch <noah@leadboat.com> — 2024-10-04T02:33:37Z

    On Thu, Oct 03, 2024 at 02:17:15PM -0400, Tom Lane wrote:
    > This could stand an additional regression test case perhaps,
    > but the core tests don't have a suitable opclass at hand.
    > Maybe we could test it in some contrib module, but that
    > seems a shade hacky.
    > 
    > Thoughts?
    
    For contrib/citext/sql/create_index_acl.sql, I settled on testing in contrib.
    I valued the test fidelity of a real opclass more than I disliked the use of
    contrib.  The distinction between the various parts of check-world is blurry
    to non-hackers, so I expect it won't bother them.
    
    
    
    
  7. Re: BUG #18637: CREATE INDEX won't look up operator classes in search_path if PARTITION BY is specified

    Tom Lane <tgl@sss.pgh.pa.us> — 2024-10-05T18:48:05Z

    Noah Misch <noah@leadboat.com> writes:
    > On Thu, Oct 03, 2024 at 02:17:15PM -0400, Tom Lane wrote:
    >> This could stand an additional regression test case perhaps,
    >> but the core tests don't have a suitable opclass at hand.
    >> Maybe we could test it in some contrib module, but that
    >> seems a shade hacky.
    
    > For contrib/citext/sql/create_index_acl.sql, I settled on testing in contrib.
    > I valued the test fidelity of a real opclass more than I disliked the use of
    > contrib.  The distinction between the various parts of check-world is blurry
    > to non-hackers, so I expect it won't bother them.
    
    Agreed.  Pushed it with a test added to contrib/seg, just to be
    different.
    
    			regards, tom lane