Skip to content

Commit e839c8e

Browse files
committed
Create functions pg_set_relation_stats, pg_clear_relation_stats.
These functions are used to tweak statistics on any relation, provided that the user has MAINTAIN privilege on the relation, or is the database owner. Bump catalog version. Author: Corey Huinker Discussion: https://postgr.es/m/CADkLM=eErgzn7ECDpwFcptJKOk9SxZEk5Pot4d94eVTZsvj3gw@mail.gmail.com
1 parent 6f782a2 commit e839c8e

File tree

12 files changed

+700
-3
lines changed

12 files changed

+700
-3
lines changed

doc/src/sgml/func.sgml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30135,6 +30135,100 @@ DETAIL: Make sure pg_wal_replay_wait() isn't called within a transaction with a
3013530135
</tgroup>
3013630136
</table>
3013730137

30138+
<para>
30139+
<xref linkend="functions-admin-statsmod"/> lists functions used to
30140+
manipulate statistics.
30141+
<warning>
30142+
<para>
30143+
Changes made by these statistics manipulation functions are likely to be
30144+
overwritten by <link linkend="autovacuum">autovacuum</link> (or manual
30145+
<command>VACUUM</command> or <command>ANALYZE</command>) and should be
30146+
considered temporary.
30147+
</para>
30148+
</warning>
30149+
</para>
30150+
30151+
<table id="functions-admin-statsmod">
30152+
<title>Database Object Statistics Manipulation Functions</title>
30153+
<tgroup cols="1">
30154+
<thead>
30155+
<row>
30156+
<entry role="func_table_entry"><para role="func_signature">
30157+
Function
30158+
</para>
30159+
<para>
30160+
Description
30161+
</para></entry>
30162+
</row>
30163+
</thead>
30164+
30165+
<tbody>
30166+
<row>
30167+
<entry role="func_table_entry">
30168+
<para role="func_signature">
30169+
<indexterm>
30170+
<primary>pg_set_relation_stats</primary>
30171+
</indexterm>
30172+
<function>pg_set_relation_stats</function> (
30173+
<parameter>relation</parameter> <type>regclass</type>
30174+
<optional>, <parameter>relpages</parameter> <type>integer</type></optional>
30175+
<optional>, <parameter>reltuples</parameter> <type>real</type></optional>
30176+
<optional>, <parameter>relallvisible</parameter> <type>integer</type></optional> )
30177+
<returnvalue>boolean</returnvalue>
30178+
</para>
30179+
<para>
30180+
Updates relation-level statistics for the given relation to the
30181+
specified values. The parameters correspond to columns in <link
30182+
linkend="catalog-pg-class"><structname>pg_class</structname></link>. Unspecified
30183+
or <literal>NULL</literal> values leave the setting
30184+
unchanged. Returns <literal>true</literal> if a change was made;
30185+
<literal>false</literal> otherwise.
30186+
</para>
30187+
<para>
30188+
Ordinarily, these statistics are collected automatically or updated
30189+
as a part of <xref linkend="sql-vacuum"/> or <xref
30190+
linkend="sql-analyze"/>, so it's not necessary to call this
30191+
function. However, it may be useful when testing the effects of
30192+
statistics on the planner to understand or anticipate plan changes.
30193+
</para>
30194+
<para>
30195+
The caller must have the <literal>MAINTAIN</literal> privilege on
30196+
the table or be the owner of the database.
30197+
</para>
30198+
<para>
30199+
The value of <structfield>relpages</structfield> must be greater than
30200+
or equal to <literal>0</literal>,
30201+
<structfield>reltuples</structfield> must be greater than or equal to
30202+
<literal>-1.0</literal>, and <structfield>relallvisible</structfield>
30203+
must be greater than or equal to <literal>0</literal>.
30204+
</para>
30205+
</entry>
30206+
</row>
30207+
30208+
<row>
30209+
<entry role="func_table_entry">
30210+
<para role="func_signature">
30211+
<indexterm>
30212+
<primary>pg_clear_relation_stats</primary>
30213+
</indexterm>
30214+
<function>pg_clear_relation_stats</function> ( <parameter>relation</parameter> <type>regclass</type> )
30215+
<returnvalue>boolean</returnvalue>
30216+
</para>
30217+
<para>
30218+
Clears table-level statistics for the given relation, as though the
30219+
table was newly created. Returns <literal>true</literal> if a change
30220+
was made; <literal>false</literal> otherwise.
30221+
</para>
30222+
<para>
30223+
The caller must have the <literal>MAINTAIN</literal> privilege on
30224+
the table or be the owner of the database.
30225+
</para>
30226+
</entry>
30227+
</row>
30228+
</tbody>
30229+
</tgroup>
30230+
</table>
30231+
3013830232
<para>
3013930233
<xref linkend="functions-info-partition"/> lists functions that provide
3014030234
information about the structure of partitioned tables.

src/backend/catalog/system_functions.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,16 @@ LANGUAGE INTERNAL
639639
CALLED ON NULL INPUT VOLATILE PARALLEL SAFE
640640
AS 'pg_stat_reset_slru';
641641

642+
CREATE OR REPLACE FUNCTION
643+
pg_set_relation_stats(relation regclass,
644+
relpages integer DEFAULT NULL,
645+
reltuples real DEFAULT NULL,
646+
relallvisible integer DEFAULT NULL)
647+
RETURNS bool
648+
LANGUAGE INTERNAL
649+
CALLED ON NULL INPUT VOLATILE
650+
AS 'pg_set_relation_stats';
651+
642652
--
643653
-- The default permissions for functions mean that anyone can execute them.
644654
-- A number of functions shouldn't be executable by just anyone, but rather

src/backend/statistics/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ OBJS = \
1616
dependencies.o \
1717
extended_stats.o \
1818
mcv.o \
19-
mvdistinct.o
19+
mvdistinct.o \
20+
relation_stats.o \
21+
stat_utils.o
2022

2123
include $(top_srcdir)/src/backend/common.mk

src/backend/statistics/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ backend_sources += files(
55
'extended_stats.c',
66
'mcv.c',
77
'mvdistinct.c',
8+
'relation_stats.c',
9+
'stat_utils.c'
810
)
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*-------------------------------------------------------------------------
2+
* relation_stats.c
3+
*
4+
* PostgreSQL relation statistics manipulation
5+
*
6+
* Code supporting the direct import of relation statistics, similar to
7+
* what is done by the ANALYZE command.
8+
*
9+
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10+
* Portions Copyright (c) 1994, Regents of the University of California
11+
*
12+
* IDENTIFICATION
13+
* src/backend/statistics/relation_stats.c
14+
*
15+
*-------------------------------------------------------------------------
16+
*/
17+
18+
#include "postgres.h"
19+
20+
#include "access/heapam.h"
21+
#include "catalog/indexing.h"
22+
#include "statistics/stat_utils.h"
23+
#include "utils/fmgrprotos.h"
24+
#include "utils/syscache.h"
25+
26+
#define DEFAULT_RELPAGES Int32GetDatum(0)
27+
#define DEFAULT_RELTUPLES Float4GetDatum(-1.0)
28+
#define DEFAULT_RELALLVISIBLE Int32GetDatum(0)
29+
30+
/*
31+
* Positional argument numbers, names, and types for
32+
* relation_statistics_update().
33+
*/
34+
35+
enum relation_stats_argnum
36+
{
37+
RELATION_ARG = 0,
38+
RELPAGES_ARG,
39+
RELTUPLES_ARG,
40+
RELALLVISIBLE_ARG,
41+
NUM_RELATION_STATS_ARGS
42+
};
43+
44+
static struct StatsArgInfo relarginfo[] =
45+
{
46+
[RELATION_ARG] = {"relation", REGCLASSOID},
47+
[RELPAGES_ARG] = {"relpages", INT4OID},
48+
[RELTUPLES_ARG] = {"reltuples", FLOAT4OID},
49+
[RELALLVISIBLE_ARG] = {"relallvisible", INT4OID},
50+
[NUM_RELATION_STATS_ARGS] = {0}
51+
};
52+
53+
static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel);
54+
55+
/*
56+
* Internal function for modifying statistics for a relation.
57+
*/
58+
static bool
59+
relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
60+
{
61+
Oid reloid;
62+
Relation crel;
63+
HeapTuple ctup;
64+
Form_pg_class pgcform;
65+
int replaces[3] = {0};
66+
Datum values[3] = {0};
67+
bool nulls[3] = {0};
68+
int ncols = 0;
69+
TupleDesc tupdesc;
70+
HeapTuple newtup;
71+
72+
73+
stats_check_required_arg(fcinfo, relarginfo, RELATION_ARG);
74+
reloid = PG_GETARG_OID(RELATION_ARG);
75+
76+
stats_lock_check_privileges(reloid);
77+
78+
/*
79+
* Take RowExclusiveLock on pg_class, consistent with
80+
* vac_update_relstats().
81+
*/
82+
crel = table_open(RelationRelationId, RowExclusiveLock);
83+
84+
tupdesc = RelationGetDescr(crel);
85+
ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
86+
if (!HeapTupleIsValid(ctup))
87+
{
88+
ereport(elevel,
89+
(errcode(ERRCODE_OBJECT_IN_USE),
90+
errmsg("pg_class entry for relid %u not found", reloid)));
91+
table_close(crel, RowExclusiveLock);
92+
return false;
93+
}
94+
95+
pgcform = (Form_pg_class) GETSTRUCT(ctup);
96+
97+
/* relpages */
98+
if (!PG_ARGISNULL(RELPAGES_ARG))
99+
{
100+
int32 relpages = PG_GETARG_INT32(RELPAGES_ARG);
101+
102+
if (relpages < -1)
103+
{
104+
ereport(elevel,
105+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
106+
errmsg("relpages cannot be < -1")));
107+
table_close(crel, RowExclusiveLock);
108+
return false;
109+
}
110+
111+
if (relpages != pgcform->relpages)
112+
{
113+
replaces[ncols] = Anum_pg_class_relpages;
114+
values[ncols] = Int32GetDatum(relpages);
115+
ncols++;
116+
}
117+
}
118+
119+
if (!PG_ARGISNULL(RELTUPLES_ARG))
120+
{
121+
float reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG);
122+
123+
if (reltuples < -1.0)
124+
{
125+
ereport(elevel,
126+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
127+
errmsg("reltuples cannot be < -1.0")));
128+
table_close(crel, RowExclusiveLock);
129+
return false;
130+
}
131+
132+
if (reltuples != pgcform->reltuples)
133+
{
134+
replaces[ncols] = Anum_pg_class_reltuples;
135+
values[ncols] = Float4GetDatum(reltuples);
136+
ncols++;
137+
}
138+
}
139+
140+
if (!PG_ARGISNULL(RELALLVISIBLE_ARG))
141+
{
142+
int32 relallvisible = PG_GETARG_INT32(RELALLVISIBLE_ARG);
143+
144+
if (relallvisible < 0)
145+
{
146+
ereport(elevel,
147+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
148+
errmsg("relallvisible cannot be < 0")));
149+
table_close(crel, RowExclusiveLock);
150+
return false;
151+
}
152+
153+
if (relallvisible != pgcform->relallvisible)
154+
{
155+
replaces[ncols] = Anum_pg_class_relallvisible;
156+
values[ncols] = Int32GetDatum(relallvisible);
157+
ncols++;
158+
}
159+
}
160+
161+
/* only update pg_class if there is a meaningful change */
162+
if (ncols == 0)
163+
{
164+
table_close(crel, RowExclusiveLock);
165+
return false;
166+
}
167+
168+
newtup = heap_modify_tuple_by_cols(ctup, tupdesc, ncols, replaces, values,
169+
nulls);
170+
171+
CatalogTupleUpdate(crel, &newtup->t_self, newtup);
172+
heap_freetuple(newtup);
173+
174+
/* release the lock, consistent with vac_update_relstats() */
175+
table_close(crel, RowExclusiveLock);
176+
177+
return true;
178+
}
179+
180+
/*
181+
* Set statistics for a given pg_class entry.
182+
*/
183+
Datum
184+
pg_set_relation_stats(PG_FUNCTION_ARGS)
185+
{
186+
PG_RETURN_BOOL(relation_statistics_update(fcinfo, ERROR));
187+
}
188+
189+
/*
190+
* Clear statistics for a given pg_class entry; that is, set back to initial
191+
* stats for a newly-created table.
192+
*/
193+
Datum
194+
pg_clear_relation_stats(PG_FUNCTION_ARGS)
195+
{
196+
LOCAL_FCINFO(newfcinfo, 4);
197+
198+
InitFunctionCallInfoData(*newfcinfo, NULL, 4, InvalidOid, NULL, NULL);
199+
200+
newfcinfo->args[0].value = PG_GETARG_OID(0);
201+
newfcinfo->args[0].isnull = PG_ARGISNULL(0);
202+
newfcinfo->args[1].value = DEFAULT_RELPAGES;
203+
newfcinfo->args[1].isnull = false;
204+
newfcinfo->args[2].value = DEFAULT_RELTUPLES;
205+
newfcinfo->args[2].isnull = false;
206+
newfcinfo->args[3].value = DEFAULT_RELALLVISIBLE;
207+
newfcinfo->args[3].isnull = false;
208+
209+
PG_RETURN_BOOL(relation_statistics_update(newfcinfo, ERROR));
210+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy