Hi,

On 2018-06-14 00:34:54 +0200, Vik Fearing wrote:
> I just noticed a problem with log_statement = 'ddl' and log_line_prefix
> containing '%x'.  If the statement is the first in the transaction, it
> will be logged before it is executed, and more importantly, before a
> transaction ID is assigned.  That means that %x will be 0.

This isn't particularly related to DDL, no? It's a general weakness of
how %x is handled. What's even worse is that by
log_min_duration_statement time the xid is already cleared out, when
using a single-statement transaction.


> If the administrator has configured postgres like this in order to ease
> PITR on bad DDL, it's actually of no use whatsoever and they'll have to
> use pg_waldump to try to figure things out.

To me that part seems like it'd be better handled if we had an option
that allows to log at a time where the xid is already assigned. Making
log_statement assign xids imo has a number of problems, but preserving
the xid for logging at the *end* of a statement should be much less
problematic.


> I'm undecided whether this is a bugfix or an improvement.  I'm leaning
> towards bugfix.

It's been reported a couple times, without anybody working to fix
it. Your fix has a noticable regression potential, so I'm not
immediately in favor of backpatching.


> -- 
> Vik Fearing                                          +33 6 46 75 15 36
> http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support

> diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
> index f4133953be..27027a0fa8 100644
> --- a/src/backend/tcop/postgres.c
> +++ b/src/backend/tcop/postgres.c
> @@ -38,6 +38,7 @@
>  
>  #include "access/parallel.h"
>  #include "access/printtup.h"
> +#include "access/transam.h"
>  #include "access/xact.h"
>  #include "catalog/pg_type.h"
>  #include "commands/async.h"
> @@ -2098,16 +2099,31 @@ check_log_statement(List *stmt_list)
>  
>       if (log_statement == LOGSTMT_NONE)
>               return false;
> -     if (log_statement == LOGSTMT_ALL)
> +
> +     /*
> +      * If we're supposed to log mod or ddl statements, we need to make sure 
> we
> +      * have a TransactionId so it appears in log_line_prefix's %x wildcard.
> +      * If the user is logging all statements, we can fast-track out if we
> +      * already have a TransactionId, otherwise we need to loop through the
> +      * statements.
> +      */
> +     if (log_statement == LOGSTMT_ALL && 
> TransactionIdIsValid(GetTopTransactionIdIfAny()))
>               return true;
>
>       /* Else we have to inspect the statement(s) to see whether to log */
>       foreach(stmt_item, stmt_list)
>       {
>               Node       *stmt = (Node *) lfirst(stmt_item);
> +             LogStmtLevel level = GetCommandLogLevel(stmt);
> +
> +             if (level <= log_statement)
> +             {
> +                     /* Make sure we have a TransactionId for mod and ddl 
> statements. */
> +                     if (level == LOGSTMT_DDL || level == LOGSTMT_MOD)
> +                             (void) GetTopTransactionId();
>  
> -             if (GetCommandLogLevel(stmt) <= log_statement)
>                       return true;
> +             }
>       }

I'm not at all on board with this.  For one this'll break in a number of
weird ways on a standby (wrong error messages at the least). For another
it increases the overhead of logging quite noticably. Thirdly moving
transaction assignment to a different place based on logging settings
seems like it'll be very confusing too.

Greetings,

Andres Freund

Reply via email to