Thread

Commits

  1. Improve management of statement timeouts.

  2. Reset statement_timeout between queries of a multi-query string.

  3. Rearm statement_timeout after each executed query.

  1. BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    The Post Office <noreply@postgresql.org> — 2019-10-03T06:38:33Z

    The following bug has been logged on the website:
    
    Bug reference:      16035
    Logged by:          Raj Mohite
    Email address:      rmohite@xento.com
    PostgreSQL version: 10.8
    Operating system:   Windows 10
    Description:        
    
    I have created a simple sql where I have added STATEMENT_TIMEOUT = 1 seconds
    and added explicit delay(pg_sleep(5) ) of 5 seconds inside CTE. 
    
    Below sql should get killed after 1 second but looks like it is running for
    5 seconds.
    
    SET STATEMENT_TIMEOUT = '1s';SELECT * FROM ( WITH test AS ( SELECT
    pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    
    Note: If we remove the quoted string 'Billy' AS emp_name  from above sql
    then proper timeout is getting applied. If we keep quoted string -- 'Billy'
    AS emp_name in the comment then also it doesn't work.
    
    Solution: We are still finding the root cause for the above behavior but I
    found that if we will put the SET STATEMENT_TIMEOUT before and after the sql
    then it working fine.
    
    Example:
    SET STATEMENT_TIMEOUT = '3s';SELECT * FROM ( WITH test AS ( SELECT
    pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;SET
    STATEMENT_TIMEOUT = '1s';  
    
    Above example will timeout after 3 seconds i.e. it will consider the 1st
    timeout value.
    
    Can you please help us to know why STATEMENT_TIMEOUT is not working in first
    example?
    
    
  2. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tom Lane <tgl@sss.pgh.pa.us> — 2019-10-03T14:51:46Z

    [ cc'ing Tatsuo and Andres, as authors of the relevant commit ]
    
    PG Bug reporting form <noreply@postgresql.org> writes:
    > PostgreSQL version: 10.8
    
    > Below sql should get killed after 1 second but looks like it is running for
    > 5 seconds.
    
    > SET STATEMENT_TIMEOUT = '1s';SELECT * FROM ( WITH test AS ( SELECT
    > pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    
    I can reproduce this in v10, but only if I submit the two statements as
    a single query string:
    
    psql (10.10)
    Type "help" for help.
    
    regression=# \timing
    Timing is on.
    regression=# SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT 
    pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
     ?column? 
    ----------
            1
    (1 row)
    
    Time: 5007.648 ms (00:05.008)
    
    If they're sent as separate statements then it works as expected:
    
    psql (10.10)
    Type "help" for help.
    
    regression=# \timing
    Timing is on.
    regression=# SET STATEMENT_TIMEOUT = '1s';SELECT * FROM ( WITH test AS ( SELECT
    pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    SET
    Time: 0.635 ms
    ERROR:  canceling statement due to statement timeout
    Time: 1000.707 ms (00:01.001)
    
    In v11 and up it works the same either way:
    
    psql (11.5)
    Type "help" for help.
    
    regression=# \timing
    Timing is on.
    regression=# SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT 
    pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    ERROR:  canceling statement due to statement timeout
    Time: 1001.187 ms (00:01.001)
    
    ... or does it?
    
    regression=# SET STATEMENT_TIMEOUT = '10s';
    SET
    Time: 0.462 ms
    regression=# SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT 
    pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
     ?column? 
    ----------
            1
    (1 row)
    
    Time: 5005.946 ms (00:05.006)
    
    The v10-and-below behavior is consistent with the idea that the initial
    value of statement_timeout is applied across the whole multi-statement
    query string.  Since you didn't set statement_timeout till after the query
    string started, the new value doesn't apply until the next submitted
    command.
    
    The newer behavior is simply not very consistent.  If you had a prevailing
    statement_timeout then it continues to apply; but if you didn't, and you
    set one, then it's armed immediately and applies to the rest of the query
    string (as a whole, not per-statement).
    
    The change in behavior seems to be a consequence of f8e5f156b,
    which made start_xact_command do this unconditionally:
    
    +   /*
    +    * Start statement timeout if necessary.  Note that this'll intentionally
    +    * not reset the clock on an already started timeout, to avoid the timing
    +    * overhead when start_xact_command() is invoked repeatedly, without an
    +    * interceding finish_xact_command() (e.g. parse/bind/execute).  If that's
    +    * not desired, the timeout has to be disabled explicitly.
    +    */
    +   enable_statement_timeout();
    
    The commit message claims that this only affected extended query
    protocol, but that's obviously false, because start_xact_command
    is also called by exec_simple_query.
    
    Not sure what if anything we should do about this.  The semantics
    of SET within a multi-statement string have always been pretty
    squishy: most variables will affect the remaining statements, but
    a few won't.  But I don't like the fact that simple query's timeout
    behavior can no longer be categorized as either of those alternatives.
    "It affects the later statements, except when it doesn't" seems
    unsatisfactory.
    
    tl;dr: I do not think this is buggy in v10.  But arguably there's
    a bug in later branches, and they need to go back to behaving
    like v10.
    
    			regards, tom lane
    
    
    
    
  3. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tatsuo Ishii <ishii@sraoss.co.jp> — 2019-10-04T08:10:08Z

    > [ cc'ing Tatsuo and Andres, as authors of the relevant commit ]
    > 
    > PG Bug reporting form <noreply@postgresql.org> writes:
    >> PostgreSQL version: 10.8
    > 
    >> Below sql should get killed after 1 second but looks like it is running for
    >> 5 seconds.
    > 
    >> SET STATEMENT_TIMEOUT = '1s';SELECT * FROM ( WITH test AS ( SELECT
    >> pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    > 
    > I can reproduce this in v10, but only if I submit the two statements as
    > a single query string:
    > 
    > psql (10.10)
    > Type "help" for help.
    > 
    > regression=# \timing
    > Timing is on.
    > regression=# SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT 
    > pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    >  ?column? 
    > ----------
    >         1
    > (1 row)
    > 
    > Time: 5007.648 ms (00:05.008)
    > 
    > If they're sent as separate statements then it works as expected:
    > 
    > psql (10.10)
    > Type "help" for help.
    > 
    > regression=# \timing
    > Timing is on.
    > regression=# SET STATEMENT_TIMEOUT = '1s';SELECT * FROM ( WITH test AS ( SELECT
    > pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    > SET
    > Time: 0.635 ms
    > ERROR:  canceling statement due to statement timeout
    > Time: 1000.707 ms (00:01.001)
    > 
    > In v11 and up it works the same either way:
    > 
    > psql (11.5)
    > Type "help" for help.
    > 
    > regression=# \timing
    > Timing is on.
    > regression=# SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT 
    > pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    > ERROR:  canceling statement due to statement timeout
    > Time: 1001.187 ms (00:01.001)
    > 
    > ... or does it?
    > 
    > regression=# SET STATEMENT_TIMEOUT = '10s';
    > SET
    > Time: 0.462 ms
    > regression=# SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT 
    > pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    >  ?column? 
    > ----------
    >         1
    > (1 row)
    > 
    > Time: 5005.946 ms (00:05.006)
    > 
    > The v10-and-below behavior is consistent with the idea that the initial
    > value of statement_timeout is applied across the whole multi-statement
    > query string.  Since you didn't set statement_timeout till after the query
    > string started, the new value doesn't apply until the next submitted
    > command.
    > 
    > The newer behavior is simply not very consistent.  If you had a prevailing
    > statement_timeout then it continues to apply; but if you didn't, and you
    > set one, then it's armed immediately and applies to the rest of the query
    > string (as a whole, not per-statement).
    > 
    > The change in behavior seems to be a consequence of f8e5f156b,
    > which made start_xact_command do this unconditionally:
    > 
    > +   /*
    > +    * Start statement timeout if necessary.  Note that this'll intentionally
    > +    * not reset the clock on an already started timeout, to avoid the timing
    > +    * overhead when start_xact_command() is invoked repeatedly, without an
    > +    * interceding finish_xact_command() (e.g. parse/bind/execute).  If that's
    > +    * not desired, the timeout has to be disabled explicitly.
    > +    */
    > +   enable_statement_timeout();
    > 
    > The commit message claims that this only affected extended query
    > protocol, but that's obviously false, because start_xact_command
    > is also called by exec_simple_query.
    > 
    > Not sure what if anything we should do about this.  The semantics
    > of SET within a multi-statement string have always been pretty
    > squishy: most variables will affect the remaining statements, but
    > a few won't.  But I don't like the fact that simple query's timeout
    > behavior can no longer be categorized as either of those alternatives.
    > "It affects the later statements, except when it doesn't" seems
    > unsatisfactory.
    > 
    > tl;dr: I do not think this is buggy in v10.  But arguably there's
    > a bug in later branches, and they need to go back to behaving
    > like v10.
    
    I understand the original reporter's complain. Also I understand Tom's
    complain to v11's behavior. I will look into the v11 (and above) code.
    
    Best regards,
    --
    Tatsuo Ishii
    SRA OSS, Inc. Japan
    English: http://www.sraoss.co.jp/index_en.php
    Japanese:http://www.sraoss.co.jp
    
    
    
    
  4. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tatsuo Ishii <ishii@sraoss.co.jp> — 2019-10-06T07:22:20Z

    >> tl;dr: I do not think this is buggy in v10.  But arguably there's
    >> a bug in later branches, and they need to go back to behaving
    >> like v10.
    > 
    > I understand the original reporter's complain. Also I understand Tom's
    > complain to v11's behavior. I will look into the v11 (and above) code.
    
    I admit v11's current behavior is inconstant, but I am not sue going
    to back V10's behavior is a good idea.
    
    With attached patch (against master), SET STATEMENT_TIMEOUT
    immediately affects to subsequent commands in the multi statement. I
    think this is not only more intuitive than v10's behavior but it meets
    the original reporter's expectation.
    
    SET STATEMENT_TIMEOUT = '10s';
    SET
    Time: 0.418 ms
    -- SELECT timeout in 1 second.
    SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    ERROR:  canceling statement due to statement timeout
    Time: 1001.107 ms (00:01.001)
    
    Here are results of test cases attached (statement_timeout.sql).
    
    \timing
    Timing is on.
    -- SELECT timeout in 1 second.
    SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    psql:/home/t-ishii/tmp/statement_timeout.sql:3: ERROR:  canceling statement due to statement timeout
    Time: 1001.138 ms (00:01.001)
    SET STATEMENT_TIMEOUT = '10s';
    SET
    Time: 0.434 ms
    -- SELECT timeout in 1 second.
    SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    psql:/home/t-ishii/tmp/statement_timeout.sql:7: ERROR:  canceling statement due to statement timeout
    Time: 1000.978 ms (00:01.001)
    -- This time SELECT succeeds and STATEMENT_TIMEOUT is set to 8 secinds.
    SET STATEMENT_TIMEOUT = '8s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
     ?column? 
    ----------
            1
    (1 row)
    
    Time: 5004.886 ms (00:05.005)
    SHOW STATEMENT_TIMEOUT;
     statement_timeout 
    -------------------
     8s
    (1 row)
    
    Time: 0.433 ms
    -- Following SELECT succeeds because now statement_timeout value is 8 seconds..
    SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
     ?column? 
    ----------
            1
    (1 row)
    
    Time: 5006.196 ms (00:05.006)
    
  5. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tatsuo Ishii <ishii@sraoss.co.jp> — 2019-10-21T05:02:17Z

    If there's no objection, I would like to commit/push the diff.
    
    > I admit v11's current behavior is inconstant, but I am not sue going
    > to back V10's behavior is a good idea.
    > 
    > With attached patch (against master), SET STATEMENT_TIMEOUT
    > immediately affects to subsequent commands in the multi statement. I
    > think this is not only more intuitive than v10's behavior but it meets
    > the original reporter's expectation.
    > 
    > SET STATEMENT_TIMEOUT = '10s';
    > SET
    > Time: 0.418 ms
    > -- SELECT timeout in 1 second.
    > SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    > ERROR:  canceling statement due to statement timeout
    > Time: 1001.107 ms (00:01.001)
    > 
    > Here are results of test cases attached (statement_timeout.sql).
    > 
    > \timing
    > Timing is on.
    > -- SELECT timeout in 1 second.
    > SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    > psql:/home/t-ishii/tmp/statement_timeout.sql:3: ERROR:  canceling statement due to statement timeout
    > Time: 1001.138 ms (00:01.001)
    > SET STATEMENT_TIMEOUT = '10s';
    > SET
    > Time: 0.434 ms
    > -- SELECT timeout in 1 second.
    > SET STATEMENT_TIMEOUT = '1s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    > psql:/home/t-ishii/tmp/statement_timeout.sql:7: ERROR:  canceling statement due to statement timeout
    > Time: 1000.978 ms (00:01.001)
    > -- This time SELECT succeeds and STATEMENT_TIMEOUT is set to 8 secinds.
    > SET STATEMENT_TIMEOUT = '8s'\;SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    >  ?column? 
    > ----------
    >         1
    > (1 row)
    > 
    > Time: 5004.886 ms (00:05.005)
    > SHOW STATEMENT_TIMEOUT;
    >  statement_timeout 
    > -------------------
    >  8s
    > (1 row)
    > 
    > Time: 0.433 ms
    > -- Following SELECT succeeds because now statement_timeout value is 8 seconds..
    > SELECT * FROM ( WITH test AS ( SELECT pg_sleep(5), 'Billy' as emp_name ) SELECT 1 FROM test ) AS sub;
    >  ?column? 
    > ----------
    >         1
    > (1 row)
    > 
    > Time: 5006.196 ms (00:05.006)
    
    
    
    
  6. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tom Lane <tgl@sss.pgh.pa.us> — 2019-10-21T05:03:54Z

    Tatsuo Ishii <ishii@sraoss.co.jp> writes:
    > If there's no objection, I would like to commit/push the diff.
    
    I'd like to look at the patch, but I just got back from pgconf.eu
    and haven't had time yet.
    
    			regards, tom lane
    
    
    
    
  7. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tom Lane <tgl@sss.pgh.pa.us> — 2019-10-21T23:02:05Z

    Tatsuo Ishii <ishii@sraoss.co.jp> writes:
    >>> tl;dr: I do not think this is buggy in v10.  But arguably there's
    >>> a bug in later branches, and they need to go back to behaving
    >>> like v10.
    
    >> I understand the original reporter's complain. Also I understand Tom's
    >> complain to v11's behavior. I will look into the v11 (and above) code.
    
    > I admit v11's current behavior is inconstant, but I am not sue going
    > to back V10's behavior is a good idea.
    > With attached patch (against master), SET STATEMENT_TIMEOUT
    > immediately affects to subsequent commands in the multi statement. I
    > think this is not only more intuitive than v10's behavior but it meets
    > the original reporter's expectation.
    
    Hm.  So, okay, that is a nicer API probably, but note that it also
    has the effect that the timeout starts over again for each statement
    in the string, while before it applied to the string as a whole.
    Are we okay with that change?  (I've not yet looked to see if it's
    documented anywhere that it works that way...)  It's kind of tossing
    some of the optimization intended by f8e5f156b overboard, since when
    a timeout is active we'll be doing timeout calculations for each
    statement in the string.
    
    Anyway, granting that we want the definitional change, I still
    don't like anything about this patch.  The proposed test
    
    +        if (!doing_extended_query_message ||
    +            (!stmt_timeout_active && doing_extended_query_message))
    
    is unreadably complicated and repetitive, and it's undocumented,
    and it makes timeout handling work quite differently in the simple
    and extended query paths, and it will cause excess timeout calculations
    (over and above the newly-necessary ones) because it will force a new
    timeout calculation for each start_xact_command call in the simple query
    path (yes, we do more than one of those per statement in common cases).
    Plus it makes the semantics of stmt_timeout_active rather unclear.
    
    I think if we want to do this, the way to do it is to add another
    disable_statement_timeout call while finishing up a non-last query
    in exec_simple_query, as per 0001 below.  That adds no extra overhead
    unless we have a multi-statement string, and it is much more parallel
    to the way things are done for extended protocol.
    
    However ... as I was looking at this, I realized that I didn't like
    anything about commit f8e5f156b either.  It introduces private state
    in postgres.c that has to be kept in sync with state in timeout.c.
    We already found one bug in that (cf be42015fc), and I have little
    faith that there aren't others, and no faith at all that we won't
    introduce more later.  The right way to manage that, I think, is to
    extend timeout.c to allow inquiring whether the timeout is active,
    as per 0002 below, so that timeout.c's state is the single source of
    truth about this.  Maintaining the extra state needed to make this
    cheap allows some other small simplifications/speedups, too, mainly
    that we can skip useless searches of the active_timeouts[] array.
    
    Not sure what I think about back-patching this.  We probably can't
    back-patch 0001; that's enough of a behavioral change that the cure
    seems worse than the disease.  I'm tempted though to argue that we
    should back-patch 0002, on the grounds that it prevents possible
    bugs and should save a few cycles too.
    
    			regards, tom lane
    
    
  8. Re: BUG #16035: STATEMENT_TIMEOUT not working when we have single quote usage inside CTE which is used in inner sql

    Tom Lane <tgl@sss.pgh.pa.us> — 2019-10-24T18:19:29Z

    I wrote:
    > Tatsuo Ishii <ishii@sraoss.co.jp> writes:
    >> With attached patch (against master), SET STATEMENT_TIMEOUT
    >> immediately affects to subsequent commands in the multi statement. I
    >> think this is not only more intuitive than v10's behavior but it meets
    >> the original reporter's expectation.
    
    > Hm.  So, okay, that is a nicer API probably, but note that it also
    > has the effect that the timeout starts over again for each statement
    > in the string, while before it applied to the string as a whole.
    > Are we okay with that change?  (I've not yet looked to see if it's
    > documented anywhere that it works that way...)  It's kind of tossing
    > some of the optimization intended by f8e5f156b overboard, since when
    > a timeout is active we'll be doing timeout calculations for each
    > statement in the string.
    
    I looked around, and as far as I can tell, there is no detail at all
    about this in our user-facing docs.  I think we should apply a doc
    patch more or less like the attached.  This fails to provide a complete
    spec of what the behavior used to be, but I don't much care to try to
    document that 100% exactly.
    
    Anyone have an objection to pushing ahead with this for HEAD only?
    
    			regards, tom lane