Infinite Autovacuum loop caused by failing virtual generated column expression

Started by SATYANARAYANA NARLAPURAM4 months ago7 messageshackers
Jump to latest
#1SATYANARAYANA NARLAPURAM
satyanarlapuram@gmail.com

Hi Hackers,

PG19 added support for stats on virtual generated columns [1]/messages/by-id/20250422181006.dd6f9d1d81299f5b2ad55e1a@sraoss.co.jp. Creating
extended statistics on a virtual generated column whose expression can
raise an error leads to ANALYZE failing repeatedly, and autovacuum retrying
indefinitely. This floods the server logs and also wastes resources. Vacuum
analyze on that column (without extended stats) succeeds.

In order to avoid retry storms, I think we have two options. (1)
skipping the offending row from the sample, (2) skipping the extended stats
computation for that table with a warning message. At least this avoid
autovacuum infinite retry. Attached a draft patch for the option (2).
Thoughts?

Repro:

CREATE TABLE t (
id int PRIMARY KEY,
a int,
gen int GENERATED ALWAYS AS (100 / a) VIRTUAL
);
INSERT INTO t VALUES (1, 10), (2, 5), (3, 0);

-- This succeeds (per-column stats don't evaluate the expression for
every row)
ANALYZE t;

-- Add extended statistics referencing the virtual gen col
CREATE STATISTICS t_stat ON a, gen FROM t;

-- This fails
ANALYZE t;
-- ERROR: division by zero

-- this succeeds
ANALYZE t(gen)

[1]: /messages/by-id/20250422181006.dd6f9d1d81299f5b2ad55e1a@sraoss.co.jp
/messages/by-id/20250422181006.dd6f9d1d81299f5b2ad55e1a@sraoss.co.jp

Thanks,
Satya

Attachments:

v1-0001-fix-analyze-extended-stats-virtual-gen-col.patchapplication/octet-stream; name=v1-0001-fix-analyze-extended-stats-virtual-gen-col.patchDownload+98-27
v1-0001-test-analyze-extended-stats-virtual-gen-col.patchapplication/octet-stream; name=v1-0001-test-analyze-extended-stats-virtual-gen-col.patchDownload+15-0
#2Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: SATYANARAYANA NARLAPURAM (#1)
Re: Infinite Autovacuum loop caused by failing virtual generated column expression

On Fri, 10 Apr 2026 at 21:19, SATYANARAYANA NARLAPURAM
<satyanarlapuram@gmail.com> wrote:

PG19 added support for stats on virtual generated columns [1]. Creating extended statistics on a virtual generated column whose expression can raise an error leads to ANALYZE failing repeatedly, and autovacuum retrying indefinitely. This floods the server logs and also wastes resources. Vacuum analyze on that column (without extended stats) succeeds.

True, though this is nothing new. The same thing can happen with
expression statistics on an expression that raises an error, which has
been possible since PG14.

In order to avoid retry storms, I think we have two options. (1) skipping the offending row from the sample, (2) skipping the extended stats computation for that table with a warning message. At least this avoid autovacuum infinite retry. Attached a draft patch for the option (2). Thoughts?

I'm not sure. The default retry interval is 1 minute, so it won't
exactly be a flood of messages. Also, if the error only occurs for a
small subset of rows, it's possible that retrying might succeed.

Regards,
Dean

#3Yugo Nagata
nagata@sraoss.co.jp
In reply to: Dean Rasheed (#2)
Re: Infinite Autovacuum loop caused by failing virtual generated column expression

On Sat, 11 Apr 2026 17:33:13 +0100
Dean Rasheed <dean.a.rasheed@gmail.com> wrote:

On Fri, 10 Apr 2026 at 21:19, SATYANARAYANA NARLAPURAM
<satyanarlapuram@gmail.com> wrote:

PG19 added support for stats on virtual generated columns [1]. Creating extended statistics on a virtual generated column whose expression can raise an error leads to ANALYZE failing repeatedly, and autovacuum retrying indefinitely. This floods the server logs and also wastes resources. Vacuum analyze on that column (without extended stats) succeeds.

True, though this is nothing new. The same thing can happen with
expression statistics on an expression that raises an error, which has
been possible since PG14.

Yes, this issue is not new, and I’m not aware of a way to prevent it a priori.

In order to avoid retry storms, I think we have two options. (1) skipping the offending row from the sample, (2) skipping the extended stats computation for that table with a warning message. At least this avoid autovacuum infinite retry. Attached a draft patch for the option (2). Thoughts?

I'm not sure. The default retry interval is 1 minute, so it won't
exactly be a flood of messages. Also, if the error only occurs for a
small subset of rows, it's possible that retrying might succeed.

I think it would be good to skip ANALYZE for the extended statistics that cause
errors and just emit a warning, rather than aborting ANALYZE for the entire table.
It seems reasonable to treat this as the user’s responsibility to notice the warning
and address the underlying issue.

Regards,
Yugo Nagata

--
Yugo Nagata <nagata@sraoss.co.jp>

#4SATYANARAYANA NARLAPURAM
satyanarlapuram@gmail.com
In reply to: Yugo Nagata (#3)
Re: Infinite Autovacuum loop caused by failing virtual generated column expression

Hi

On Mon, Apr 13, 2026 at 11:24 PM Yugo Nagata <nagata@sraoss.co.jp> wrote:

On Sat, 11 Apr 2026 17:33:13 +0100
Dean Rasheed <dean.a.rasheed@gmail.com> wrote:

On Fri, 10 Apr 2026 at 21:19, SATYANARAYANA NARLAPURAM
<satyanarlapuram@gmail.com> wrote:

PG19 added support for stats on virtual generated columns [1].

Creating extended statistics on a virtual generated column whose expression
can raise an error leads to ANALYZE failing repeatedly, and autovacuum
retrying indefinitely. This floods the server logs and also wastes
resources. Vacuum analyze on that column (without extended stats) succeeds.

True, though this is nothing new. The same thing can happen with
expression statistics on an expression that raises an error, which has
been possible since PG14.

Yes, this issue is not new, and I’m not aware of a way to prevent it a
priori.

In order to avoid retry storms, I think we have two options. (1)

skipping the offending row from the sample, (2) skipping the extended stats
computation for that table with a warning message. At least this avoid
autovacuum infinite retry. Attached a draft patch for the option (2).
Thoughts?

I'm not sure. The default retry interval is 1 minute, so it won't
exactly be a flood of messages. Also, if the error only occurs for a
small subset of rows, it's possible that retrying might succeed.

I think it would be good to skip ANALYZE for the extended statistics that
cause
errors and just emit a warning, rather than aborting ANALYZE for the
entire table.
It seems reasonable to treat this as the user’s responsibility to notice
the warning
and address the underlying issue.

Yugo, thanks for the comments. Could you please review the v1 patch when you
get a chance. It is in the direction you suggested.

Thanks,
Satya

#5Yugo Nagata
nagata@sraoss.co.jp
In reply to: SATYANARAYANA NARLAPURAM (#4)
Re: Infinite Autovacuum loop caused by failing virtual generated column expression

On Tue, 14 Apr 2026 00:16:42 -0700
SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com> wrote:

Hi

On Mon, Apr 13, 2026 at 11:24 PM Yugo Nagata <nagata@sraoss.co.jp> wrote:

On Sat, 11 Apr 2026 17:33:13 +0100
Dean Rasheed <dean.a.rasheed@gmail.com> wrote:

On Fri, 10 Apr 2026 at 21:19, SATYANARAYANA NARLAPURAM
<satyanarlapuram@gmail.com> wrote:

PG19 added support for stats on virtual generated columns [1].

Creating extended statistics on a virtual generated column whose expression
can raise an error leads to ANALYZE failing repeatedly, and autovacuum
retrying indefinitely. This floods the server logs and also wastes
resources. Vacuum analyze on that column (without extended stats) succeeds.

True, though this is nothing new. The same thing can happen with
expression statistics on an expression that raises an error, which has
been possible since PG14.

Yes, this issue is not new, and I’m not aware of a way to prevent it a
priori.

In order to avoid retry storms, I think we have two options. (1)

skipping the offending row from the sample, (2) skipping the extended stats
computation for that table with a warning message. At least this avoid
autovacuum infinite retry. Attached a draft patch for the option (2).
Thoughts?

I'm not sure. The default retry interval is 1 minute, so it won't
exactly be a flood of messages. Also, if the error only occurs for a
small subset of rows, it's possible that retrying might succeed.

I think it would be good to skip ANALYZE for the extended statistics that
cause
errors and just emit a warning, rather than aborting ANALYZE for the
entire table.
It seems reasonable to treat this as the user’s responsibility to notice
the warning
and address the underlying issue.

Yugo, thanks for the comments. Could you please review the v1 patch when you
get a chance. It is in the direction you suggested.

I've looked into the patch and have some comments.

The child ResourceOwner is created and released in BuildRelationExtStatistics(),
but I don't think it is necessary if we add other PG_TRY block in make_build_data()
and compute_expr_stats(). For example in make_build_data():

+                       PG_TRY();
+                       {
+                               datum = ExecEvalExpr(exprstate,
+                                                                        GetPerTupleExprContext(estate),
+                                                                        &isnull);
+                               }
+                       PG_CATCH();
+                       {
+                               ExecDropSingleTupleTableSlot(slot);
+                               FreeExecutorState(estate);
+                               PG_RE_THROW();
+                       }
+                       PG_END_TRY();

Also, we could add tests for extended statistics that do not involve virtual generated
columns, since those are not the cause root of the issue. In addition, it might be useful
to verify that non-skipped extended statistics are still computed successfully.
For example:

+CREATE TABLE expr_err (a int);
+INSERT INTO expr_err VALUES (1), (2), (3);
+CREATE STATISTICS expr_err_s1 ON ((a/0)) FROM expr_err;
+CREATE STATISTICS expr_err_s2 ON (a/0),(a+1) FROM expr_err;
+CREATE STATISTICS expr_err_s3 ON ((a+1)) FROM expr_err;
+ANALYZE expr_err;  -- should warn, not fail
+SELECT statistics_name from pg_stats_ext x
+    WHERE tablename = 'expr_err' ORDER BY ROW(x.*);

Regards,
Yugo Nagata

--
Yugo Nagata <nagata@sraoss.co.jp>

#6SATYANARAYANA NARLAPURAM
satyanarlapuram@gmail.com
In reply to: Yugo Nagata (#5)
Re: Infinite Autovacuum loop caused by failing virtual generated column expression

Hi,

On Tue, Apr 28, 2026 at 2:14 AM Yugo Nagata <nagata@sraoss.co.jp> wrote:

On Tue, 14 Apr 2026 00:16:42 -0700
SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com> wrote:

Hi

On Mon, Apr 13, 2026 at 11:24 PM Yugo Nagata <nagata@sraoss.co.jp>

wrote:

On Sat, 11 Apr 2026 17:33:13 +0100
Dean Rasheed <dean.a.rasheed@gmail.com> wrote:

On Fri, 10 Apr 2026 at 21:19, SATYANARAYANA NARLAPURAM
<satyanarlapuram@gmail.com> wrote:

PG19 added support for stats on virtual generated columns [1].

Creating extended statistics on a virtual generated column whose

expression

can raise an error leads to ANALYZE failing repeatedly, and autovacuum
retrying indefinitely. This floods the server logs and also wastes
resources. Vacuum analyze on that column (without extended stats)

succeeds.

True, though this is nothing new. The same thing can happen with
expression statistics on an expression that raises an error, which

has

been possible since PG14.

Yes, this issue is not new, and I’m not aware of a way to prevent it a
priori.

In order to avoid retry storms, I think we have two options. (1)

skipping the offending row from the sample, (2) skipping the extended

stats

computation for that table with a warning message. At least this avoid
autovacuum infinite retry. Attached a draft patch for the option (2).
Thoughts?

I'm not sure. The default retry interval is 1 minute, so it won't
exactly be a flood of messages. Also, if the error only occurs for a
small subset of rows, it's possible that retrying might succeed.

I think it would be good to skip ANALYZE for the extended statistics

that

cause
errors and just emit a warning, rather than aborting ANALYZE for the
entire table.
It seems reasonable to treat this as the user’s responsibility to

notice

the warning
and address the underlying issue.

Yugo, thanks for the comments. Could you please review the v1 patch when

you

get a chance. It is in the direction you suggested.

I've looked into the patch and have some comments.

The child ResourceOwner is created and released in
BuildRelationExtStatistics(),
but I don't think it is necessary if we add other PG_TRY block in
make_build_data()
and compute_expr_stats(). For example in make_build_data():

+                       PG_TRY();
+                       {
+                               datum = ExecEvalExpr(exprstate,
+
GetPerTupleExprContext(estate),
+
&isnull);
+                               }
+                       PG_CATCH();
+                       {
+                               ExecDropSingleTupleTableSlot(slot);
+                               FreeExecutorState(estate);
+                               PG_RE_THROW();
+                       }
+                       PG_END_TRY();

Thanks, for reviewing the patch. Agreed, please find the updated patch.

Also, we could add tests for extended statistics that do not involve
virtual generated
columns, since those are not the cause root of the issue. In addition, it
might be useful
to verify that non-skipped extended statistics are still computed
successfully.
For example:

+CREATE TABLE expr_err (a int);
+INSERT INTO expr_err VALUES (1), (2), (3);
+CREATE STATISTICS expr_err_s1 ON ((a/0)) FROM expr_err;
+CREATE STATISTICS expr_err_s2 ON (a/0),(a+1) FROM expr_err;
+CREATE STATISTICS expr_err_s3 ON ((a+1)) FROM expr_err;
+ANALYZE expr_err;  -- should warn, not fail
+SELECT statistics_name from pg_stats_ext x
+    WHERE tablename = 'expr_err' ORDER BY ROW(x.*);

Added these tests as well in the v2 patch.

Thanks,
Satya

Attachments:

v2-0001-Fix-ANALYZE-crash-on-extended-stats-with-virtual-gen.patchapplication/octet-stream; name=v2-0001-Fix-ANALYZE-crash-on-extended-stats-with-virtual-gen.patchDownload+195-95
#7Yugo Nagata
nagata@sraoss.co.jp
In reply to: SATYANARAYANA NARLAPURAM (#6)
Re: Infinite Autovacuum loop caused by failing virtual generated column expression

On Sun, 3 May 2026 11:04:59 -0700
SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com> wrote:

Thank you for updating the patch!

There are a few comments on v2 patch.

In compute_expr_stats(),

+		PG_CATCH();
+		{
+			ExecDropSingleTupleTableSlot(slot);
+			FreeExecutorState(estate);
+			PG_RE_THROW();
 		}

Should we switch the context to expr_context before releasing
slot and estate? Also, should we call MemoryContextDelete(expr_context)
to release palloc'ed memory in the loop?
(In fact, the error would not be cached in compute_expr_stats(), though,
since it would be cached in make_build_data() if any.)

Should we switch to expr_context before releasing slot and estate?
Also, should we call MemoryContextDelete(expr_context) to release
memory allocated by palloc() in the loop?

(In practice, errors would not catched in compute_expr_stats() itself,
since they would already be caught in make_build_data() if any.)

+       /*
+        * Wrap expression evaluation and stats computation in PG_TRY so
+        * that errors from evaluating expressions (e.g. division by zero
+        * in virtual generated columns) don't cause ANALYZE to fail
+        * entirely.  Skip the statistics object and issue a WARNING
+        * instead.

How about rewriting the comments to reflect the more general case?

Extended statistics involving virtual generated columns are a somewhat
special case, while errors in expression statistics seem more common
in practice. The same applies to the commit message as well.

Regards,
Yugo Nagata

--
Yugo Nagata <nagata@sraoss.co.jp>