v1-0001-fix-analyze-extended-stats-virtual-gen-col.patch
application/octet-stream
Filename: v1-0001-fix-analyze-extended-stats-virtual-gen-col.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1-0001
| File | + | − |
|---|---|---|
| src/backend/statistics/extended_stats.c | 98 | 27 |
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index 2b83355d..ba25dd62 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -33,6 +33,7 @@
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "rewrite/rewriteHandler.h"
+#include "utils/resowner.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/statistics.h"
#include "utils/acl.h"
@@ -194,42 +195,112 @@ BuildRelationExtStatistics(Relation onerel, bool inh, double totalrows,
if (stattarget == 0)
continue;
- /* evaluate expressions (if the statistics object has any) */
- data = make_build_data(onerel, stat, numrows, rows, stats, stattarget);
-
- /* compute statistic of each requested type */
- foreach(lc2, stat->types)
+ /*
+ * Wrap expression evaluation and stats computation in PG_TRY so
+ * that errors from evaluating virtual generated column expressions
+ * (e.g. division by zero) don't cause ANALYZE to fail entirely.
+ * Skip the statistics object and issue a WARNING instead.
+ *
+ * Used child ResourceOwner so that any resources allocated
+ * during expression evaluation are properly released on
+ * error without leaking.
+ */
{
- char t = (char) lfirst_int(lc2);
-
- if (t == STATS_EXT_NDISTINCT)
- ndistinct = statext_ndistinct_build(totalrows, data);
- else if (t == STATS_EXT_DEPENDENCIES)
- dependencies = statext_dependencies_build(data);
- else if (t == STATS_EXT_MCV)
- mcv = statext_mcv_build(data, totalrows, stattarget);
- else if (t == STATS_EXT_EXPRESSIONS)
+ ResourceOwner oldowner = CurrentResourceOwner;
+ ResourceOwner child;
+
+ child = ResourceOwnerCreate(oldowner, "BuildExtStatistics");
+ CurrentResourceOwner = child;
+
+ PG_TRY();
{
- AnlExprData *exprdata;
- int nexprs;
+ /* evaluate expressions (if the statistics has any) */
+ data = make_build_data(onerel, stat, numrows, rows,
+ stats, stattarget);
- /* should not happen, thanks to checks when defining stats */
- if (!stat->exprs)
- elog(ERROR, "requested expression stats, but there are no expressions");
+ /* compute statistic of each requested type */
+ foreach(lc2, stat->types)
+ {
+ char t = (char) lfirst_int(lc2);
+
+ if (t == STATS_EXT_NDISTINCT)
+ ndistinct = statext_ndistinct_build(totalrows, data);
+ else if (t == STATS_EXT_DEPENDENCIES)
+ dependencies = statext_dependencies_build(data);
+ else if (t == STATS_EXT_MCV)
+ mcv = statext_mcv_build(data, totalrows, stattarget);
+ else if (t == STATS_EXT_EXPRESSIONS)
+ {
+ AnlExprData *exprdata;
+ int nexprs;
+
+ /* should not happen, thanks to checks */
+ if (!stat->exprs)
+ elog(ERROR, "requested expression stats, but there are no expressions");
+
+ exprdata = build_expr_data(stat->exprs, stattarget);
+ nexprs = list_length(stat->exprs);
+
+ compute_expr_stats(onerel, exprdata, nexprs,
+ rows, numrows);
+
+ exprstats = serialize_expr_stats(exprdata, nexprs);
+ }
+ }
- exprdata = build_expr_data(stat->exprs, stattarget);
- nexprs = list_length(stat->exprs);
+ /* store the statistics in the catalog */
+ statext_store(stat->statOid, inh,
+ ndistinct, dependencies, mcv, exprstats, stats);
+
+ /* Success: release child ResourceOwner normally */
+ CurrentResourceOwner = oldowner;
+ ResourceOwnerRelease(child,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ false, false);
+ ResourceOwnerRelease(child,
+ RESOURCE_RELEASE_LOCKS,
+ false, false);
+ ResourceOwnerRelease(child,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ false, false);
+ ResourceOwnerDelete(child);
+ }
+ PG_CATCH();
+ {
+ ErrorData *edata;
+
+ /* Release leaked resources from the child ResourceOwner */
+ CurrentResourceOwner = child;
+ ResourceOwnerRelease(child,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ false, false);
+ ResourceOwnerRelease(child,
+ RESOURCE_RELEASE_LOCKS,
+ false, false);
+ ResourceOwnerRelease(child,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ false, false);
+ CurrentResourceOwner = oldowner;
+ ResourceOwnerDelete(child);
+
+ /* Save the error, issue a WARNING and continue */
+ MemoryContextSwitchTo(cxt);
+ edata = CopyErrorData();
+ FlushErrorState();
- compute_expr_stats(onerel, exprdata, nexprs, rows, numrows);
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING),
+ errmsg("skipping statistics object \"%s.%s\" for relation \"%s.%s\"",
+ stat->schema, stat->name,
+ get_namespace_name(onerel->rd_rel->relnamespace),
+ RelationGetRelationName(onerel)),
+ errdetail("%s", edata->message)));
- exprstats = serialize_expr_stats(exprdata, nexprs);
+ FreeErrorData(edata);
}
+ PG_END_TRY();
}
- /* store the statistics in the catalog */
- statext_store(stat->statOid, inh,
- ndistinct, dependencies, mcv, exprstats, stats);
-
/* for reporting progress */
pgstat_progress_update_param(PROGRESS_ANALYZE_EXT_STATS_COMPUTED,
++ext_cnt);