Thread

Commits

  1. Fix possible loss of sync between rectypeid and underlying PLpgSQL_type.

  1. Calling PLpgSQL function with composite type fails with an error: "ERROR: could not open relation with OID ..."

    Ashutosh Sharma <ashu.coek88@gmail.com> — 2019-12-26T10:27:18Z

    Hi All,
    
    When the following test-case is executed on master, it fails with an
    error: "ERROR:  could not open relation with OID ..."
    
    -- create a test table:
    create table tab1(a int, b text);
    
    -- create a test function:
    create or replace function f1() returns void as
    $$
    declare
       var1 tab1;
    begin
       select * into var1 from tab1;
    end
    $$ language plpgsql;
    
    -- call the test function:
    select f1();
    
    -- drop the test table and re-create it:
    drop table tab1;
    create table tab1(a int, b text);
    
    -- call the test function:
    select f1();
    
    -- call the test function once again:
    select f1(); -- this fails with an error "ERROR:  could not open
    relation with OID .."
    
    I'm trying to investigate this issue and will try to share my findings soon...
    
    --
    With Regards,
    Ashutosh Sharma
    EnterpriseDB:http://www.enterprisedb.com
    
    
    
    
  2. Re: Calling PLpgSQL function with composite type fails with an error: "ERROR: could not open relation with OID ..."

    Ashutosh Sharma <ashu.coek88@gmail.com> — 2019-12-26T11:32:05Z

    The issue here is that PLpgSQL_rec structure being updated by
    revalidate_rectypeid() is actually a local/duplicate copy of the
    PLpgSQL_rec structure available in plpgsql_HashTable (refer to
    copy_plpgsql_datums() where you would notice that if datum type is
    PLPGSQL_DTYPE_REC we actually mempcy() the PLpgSQL_rec structure
    available in func >datums[] array). This basically means that the
    rectypeid field updated post typcache entry validation in
    revalidation_rectypeid() is actually a field in duplicate copy of
    PLpgSQL_rec structure, not the original copy of it available in
    func->datums[]. Hence, when the same function is executed for the
    second time, the rectypeid field of PLpgSQL_rec structure being
    reloaded from the func->datums[] actually contains the stale value
    however the typcache entry in it is up-to-date which means
    revalidation_rectypeid() returns immediately leaving a stale value in
    rectypeid. This causes the function make_expanded_record_from_typeid()
    to use the outdated value in rec->rectypeid resulting into the given
    error.
    
    To fix this, I think instead of using rec->rectypeid field we should
    try using rec->datatype->typoid when calling
    make_expanded_record_from_typeid(). Here is the change that I'm
    suggesting:
    
    --- a/src/pl/plpgsql/src/pl_exec.c
    +++ b/src/pl/plpgsql/src/pl_exec.c
    @@ -6942,7 +6942,7 @@ make_expanded_record_for_rec(PLpgSQL_execstate *estate,
                newerh = make_expanded_record_from_exprecord(srcerh,
                                                             mcontext);
            else
    -           newerh = make_expanded_record_from_typeid(rec->rectypeid, -1,
    +          newerh = make_expanded_record_from_typeid(rec->datatype->typoid, -1,
    
    Thoughts ?
    
    --
    With Regards,
    Ashutosh Sharma
    EnterpriseDB:http://www.enterprisedb.com
    
    On Thu, Dec 26, 2019 at 3:57 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:
    >
    > Hi All,
    >
    > When the following test-case is executed on master, it fails with an
    > error: "ERROR:  could not open relation with OID ..."
    >
    > -- create a test table:
    > create table tab1(a int, b text);
    >
    > -- create a test function:
    > create or replace function f1() returns void as
    > $$
    > declare
    >    var1 tab1;
    > begin
    >    select * into var1 from tab1;
    > end
    > $$ language plpgsql;
    >
    > -- call the test function:
    > select f1();
    >
    > -- drop the test table and re-create it:
    > drop table tab1;
    > create table tab1(a int, b text);
    >
    > -- call the test function:
    > select f1();
    >
    > -- call the test function once again:
    > select f1(); -- this fails with an error "ERROR:  could not open
    > relation with OID .."
    >
    > I'm trying to investigate this issue and will try to share my findings soon...
    >
    > --
    > With Regards,
    > Ashutosh Sharma
    > EnterpriseDB:http://www.enterprisedb.com
    
    
    
    
  3. Re: Calling PLpgSQL function with composite type fails with an error: "ERROR: could not open relation with OID ..."

    Tom Lane <tgl@sss.pgh.pa.us> — 2019-12-26T20:29:56Z

    Ashutosh Sharma <ashu.coek88@gmail.com> writes:
    > The issue here is that PLpgSQL_rec structure being updated by
    > revalidate_rectypeid() is actually a local/duplicate copy of the
    > PLpgSQL_rec structure available in plpgsql_HashTable (refer to
    > copy_plpgsql_datums() where you would notice that if datum type is
    > PLPGSQL_DTYPE_REC we actually mempcy() the PLpgSQL_rec structure
    > available in func >datums[] array). This basically means that the
    > rectypeid field updated post typcache entry validation in
    > revalidation_rectypeid() is actually a field in duplicate copy of
    > PLpgSQL_rec structure, not the original copy of it available in
    > func->datums[]. Hence, when the same function is executed for the
    > second time, the rectypeid field of PLpgSQL_rec structure being
    > reloaded from the func->datums[] actually contains the stale value
    > however the typcache entry in it is up-to-date which means
    > revalidation_rectypeid() returns immediately leaving a stale value in
    > rectypeid. This causes the function make_expanded_record_from_typeid()
    > to use the outdated value in rec->rectypeid resulting into the given
    > error.
    
    Good catch!
    
    > To fix this, I think instead of using rec->rectypeid field we should
    > try using rec->datatype->typoid when calling
    > make_expanded_record_from_typeid().
    
    This is a crummy fix, though.  In the first place, if we did it like this
    we'd have to fix every other caller of revalidate_rectypeid() likewise.
    Basically the issue here is that revalidate_rectypeid() is failing to do
    what it says on the tin, and you're proposing to make the callers work
    around that instead of fixing revalidate_rectypeid().  That seems like
    an odd choice from here.
    
    More generally, the reason for the separation between PLpgSQL_rec and
    PLpgSQL_type in this part of the code is that PLpgSQL_rec.rectypeid is
    supposed to record the actual type ID currently instantiated in that
    variable (in the current function execution), whereas PLpgSQL_type is a
    cache for the last type lookup we did; that's why it's okay to share the
    latter but not the former across function executions.  So failing to
    update rec->rectypeid is almost certainly going to lead to problems
    later on.
    
    I pushed a fix that makes revalidate_rectypeid() deal with this case.
    Thanks for the report and debugging!
    
    			regards, tom lane
    
    
    
    
  4. Re: Calling PLpgSQL function with composite type fails with an error: "ERROR: could not open relation with OID ..."

    Ashutosh Sharma <ashu.coek88@gmail.com> — 2019-12-27T02:32:03Z

    On Fri, Dec 27, 2019 at 1:59 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >
    > Ashutosh Sharma <ashu.coek88@gmail.com> writes:
    > > The issue here is that PLpgSQL_rec structure being updated by
    > > revalidate_rectypeid() is actually a local/duplicate copy of the
    > > PLpgSQL_rec structure available in plpgsql_HashTable (refer to
    > > copy_plpgsql_datums() where you would notice that if datum type is
    > > PLPGSQL_DTYPE_REC we actually mempcy() the PLpgSQL_rec structure
    > > available in func >datums[] array). This basically means that the
    > > rectypeid field updated post typcache entry validation in
    > > revalidation_rectypeid() is actually a field in duplicate copy of
    > > PLpgSQL_rec structure, not the original copy of it available in
    > > func->datums[]. Hence, when the same function is executed for the
    > > second time, the rectypeid field of PLpgSQL_rec structure being
    > > reloaded from the func->datums[] actually contains the stale value
    > > however the typcache entry in it is up-to-date which means
    > > revalidation_rectypeid() returns immediately leaving a stale value in
    > > rectypeid. This causes the function make_expanded_record_from_typeid()
    > > to use the outdated value in rec->rectypeid resulting into the given
    > > error.
    >
    > Good catch!
    >
    > > To fix this, I think instead of using rec->rectypeid field we should
    > > try using rec->datatype->typoid when calling
    > > make_expanded_record_from_typeid().
    >
    > This is a crummy fix, though.  In the first place, if we did it like this
    > we'd have to fix every other caller of revalidate_rectypeid() likewise.
    > Basically the issue here is that revalidate_rectypeid() is failing to do
    > what it says on the tin, and you're proposing to make the callers work
    > around that instead of fixing revalidate_rectypeid().  That seems like
    > an odd choice from here.
    >
    > More generally, the reason for the separation between PLpgSQL_rec and
    > PLpgSQL_type in this part of the code is that PLpgSQL_rec.rectypeid is
    > supposed to record the actual type ID currently instantiated in that
    > variable (in the current function execution), whereas PLpgSQL_type is a
    > cache for the last type lookup we did; that's why it's okay to share the
    > latter but not the former across function executions.  So failing to
    > update rec->rectypeid is almost certainly going to lead to problems
    > later on.
    >
    > I pushed a fix that makes revalidate_rectypeid() deal with this case.
    > Thanks for the report and debugging!
    >
    
    Okay. Thanks for that fix. You've basically forced
    revalidate_rectypeid() to update the PLpgSQL_rec's rectypeid
    irrespective of typcache entry requires re-validation or not.
    
    --
    With Regards,
    Ashutosh Sharma
    EnterpriseDB:http://www.enterprisedb.com
    
    
    
    
  5. Re: Calling PLpgSQL function with composite type fails with an error: "ERROR: could not open relation with OID ..."

    Tom Lane <tgl@sss.pgh.pa.us> — 2019-12-27T03:50:34Z

    Ashutosh Sharma <ashu.coek88@gmail.com> writes:
    > Okay. Thanks for that fix. You've basically forced
    > revalidate_rectypeid() to update the PLpgSQL_rec's rectypeid
    > irrespective of typcache entry requires re-validation or not.
    
    Right.  The assignment is cheap enough that it hardly seems
    worth avoiding.
    
    			regards, tom lane
    
    
    
    
  6. Re: Calling PLpgSQL function with composite type fails with an error: "ERROR: could not open relation with OID ..."

    Ashutosh Sharma <ashu.coek88@gmail.com> — 2019-12-27T11:15:18Z

    On Fri, Dec 27, 2019 at 9:20 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
    >
    > Ashutosh Sharma <ashu.coek88@gmail.com> writes:
    > > Okay. Thanks for that fix. You've basically forced
    > > revalidate_rectypeid() to update the PLpgSQL_rec's rectypeid
    > > irrespective of typcache entry requires re-validation or not.
    >
    > Right.  The assignment is cheap enough that it hardly seems
    > worth avoiding.
    >
    
    Agreed.
    
    --
    With Regards,
    Ashutosh Sharma
    EnterpriseDB:http://www.enterprisedb.com