1 /*-------------------------------------------------------------------------
4 * PostgreSQL relation statistics manipulation
6 * Code supporting the direct import of relation statistics, similar to
7 * what is done by the ANALYZE command.
9 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
13 * src/backend/statistics/relation_stats.c
15 *-------------------------------------------------------------------------
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"
26 #define DEFAULT_RELPAGES Int32GetDatum(0)
27 #define DEFAULT_RELTUPLES Float4GetDatum(-1.0)
28 #define DEFAULT_RELALLVISIBLE Int32GetDatum(0)
31 * Positional argument numbers, names, and types for
32 * relation_statistics_update().
35 enum relation_stats_argnum
41 NUM_RELATION_STATS_ARGS
44 static struct StatsArgInfo relarginfo
[] =
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}
53 static bool relation_statistics_update(FunctionCallInfo fcinfo
, int elevel
);
56 * Internal function for modifying statistics for a relation.
59 relation_statistics_update(FunctionCallInfo fcinfo
, int elevel
)
64 Form_pg_class pgcform
;
65 int replaces
[3] = {0};
66 Datum values
[3] = {0};
72 stats_check_required_arg(fcinfo
, relarginfo
, RELATION_ARG
);
73 reloid
= PG_GETARG_OID(RELATION_ARG
);
75 if (RecoveryInProgress())
77 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
78 errmsg("recovery is in progress"),
79 errhint("Statistics cannot be modified during recovery.")));
81 stats_lock_check_privileges(reloid
);
84 * Take RowExclusiveLock on pg_class, consistent with
85 * vac_update_relstats().
87 crel
= table_open(RelationRelationId
, RowExclusiveLock
);
89 tupdesc
= RelationGetDescr(crel
);
90 ctup
= SearchSysCacheCopy1(RELOID
, ObjectIdGetDatum(reloid
));
91 if (!HeapTupleIsValid(ctup
))
94 (errcode(ERRCODE_OBJECT_IN_USE
),
95 errmsg("pg_class entry for relid %u not found", reloid
)));
96 table_close(crel
, RowExclusiveLock
);
100 pgcform
= (Form_pg_class
) GETSTRUCT(ctup
);
103 if (!PG_ARGISNULL(RELPAGES_ARG
))
105 int32 relpages
= PG_GETARG_INT32(RELPAGES_ARG
);
108 * Partitioned tables may have relpages=-1. Note: for relations with
109 * no storage, relpages=-1 is not used consistently, but must be
115 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
116 errmsg("relpages cannot be < -1")));
119 else if (relpages
!= pgcform
->relpages
)
121 replaces
[ncols
] = Anum_pg_class_relpages
;
122 values
[ncols
] = Int32GetDatum(relpages
);
127 if (!PG_ARGISNULL(RELTUPLES_ARG
))
129 float reltuples
= PG_GETARG_FLOAT4(RELTUPLES_ARG
);
131 if (reltuples
< -1.0)
134 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
135 errmsg("reltuples cannot be < -1.0")));
138 else if (reltuples
!= pgcform
->reltuples
)
140 replaces
[ncols
] = Anum_pg_class_reltuples
;
141 values
[ncols
] = Float4GetDatum(reltuples
);
147 if (!PG_ARGISNULL(RELALLVISIBLE_ARG
))
149 int32 relallvisible
= PG_GETARG_INT32(RELALLVISIBLE_ARG
);
151 if (relallvisible
< 0)
154 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
155 errmsg("relallvisible cannot be < 0")));
158 else if (relallvisible
!= pgcform
->relallvisible
)
160 replaces
[ncols
] = Anum_pg_class_relallvisible
;
161 values
[ncols
] = Int32GetDatum(relallvisible
);
166 /* only update pg_class if there is a meaningful change */
171 newtup
= heap_modify_tuple_by_cols(ctup
, tupdesc
, ncols
, replaces
, values
,
173 CatalogTupleUpdate(crel
, &newtup
->t_self
, newtup
);
174 heap_freetuple(newtup
);
177 /* release the lock, consistent with vac_update_relstats() */
178 table_close(crel
, RowExclusiveLock
);
180 CommandCounterIncrement();
186 * Set statistics for a given pg_class entry.
189 pg_set_relation_stats(PG_FUNCTION_ARGS
)
191 relation_statistics_update(fcinfo
, ERROR
);
196 * Clear statistics for a given pg_class entry; that is, set back to initial
197 * stats for a newly-created table.
200 pg_clear_relation_stats(PG_FUNCTION_ARGS
)
202 LOCAL_FCINFO(newfcinfo
, 4);
204 InitFunctionCallInfoData(*newfcinfo
, NULL
, 4, InvalidOid
, NULL
, NULL
);
206 newfcinfo
->args
[0].value
= PG_GETARG_OID(0);
207 newfcinfo
->args
[0].isnull
= PG_ARGISNULL(0);
208 newfcinfo
->args
[1].value
= DEFAULT_RELPAGES
;
209 newfcinfo
->args
[1].isnull
= false;
210 newfcinfo
->args
[2].value
= DEFAULT_RELTUPLES
;
211 newfcinfo
->args
[2].isnull
= false;
212 newfcinfo
->args
[3].value
= DEFAULT_RELALLVISIBLE
;
213 newfcinfo
->args
[3].isnull
= false;
215 relation_statistics_update(newfcinfo
, ERROR
);
220 pg_restore_relation_stats(PG_FUNCTION_ARGS
)
222 LOCAL_FCINFO(positional_fcinfo
, NUM_RELATION_STATS_ARGS
);
225 InitFunctionCallInfoData(*positional_fcinfo
, NULL
,
226 NUM_RELATION_STATS_ARGS
,
227 InvalidOid
, NULL
, NULL
);
229 if (!stats_fill_fcinfo_from_arg_pairs(fcinfo
, positional_fcinfo
,
230 relarginfo
, WARNING
))
233 if (!relation_statistics_update(positional_fcinfo
, WARNING
))
236 PG_RETURN_BOOL(result
);