#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/guc.h"
+#if PG_VERSION_NUM >= 90200
+#include "catalog/pg_class.h"
+#include "nodes/primnodes.h"
+#include "tcop/utility.h"
+#include "utils/rel.h"
+#include "utils/relcache.h"
+#include "utils/timestamp.h"
+#if PG_VERSION_NUM >= 90500
+#include "nodes/makefuncs.h"
+#endif
+#endif
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
static int online_analyze_threshold = 50;
static double online_analyze_min_interval = 10000;
-typedef enum
+static ExecutorEnd_hook_type oldExecutorEndHook = NULL;
+#if PG_VERSION_NUM >= 90200
+static ProcessUtility_hook_type oldProcessUtilityHook = NULL;
+#endif
+
+typedef enum
{
OATT_ALL = 0x03,
OATT_PERSISTENT = 0x01,
OATT_TEMPORARY = 0x02,
OATT_NONE = 0x00
-} OnlyneAnalyzeTableType;
+} OnlineAnalyzeTableType;
static const struct config_enum_entry online_analyze_table_type_options[] =
{
foreach(l, namelist)
{
char *curname = (char *) lfirst(l);
- Oid relOid = RangeVarGetRelid(makeRangeVarFromNameList(stringToQualifiedNameList(curname)), true);
+#if PG_VERSION_NUM >= 90200
+ Oid relOid = RangeVarGetRelid(makeRangeVarFromNameList(stringToQualifiedNameList(curname)),
+ NoLock, true);
+#else
+ Oid relOid = RangeVarGetRelid(makeRangeVarFromNameList(stringToQualifiedNameList(curname)),
+ true);
+#endif
if (relOid == InvalidOid)
{
return false;
}
-static ExecutorEnd_hook_type oldhook = NULL;
+#if PG_VERSION_NUM >= 90500
+static RangeVar*
+makeRangeVarFromOid(Oid relOid)
+{
+ return makeRangeVar(
+ get_namespace_name(get_rel_namespace(relOid)),
+ get_rel_name(relOid),
+ -1
+ );
+
+}
+#endif
static void
-makeAnalyze(Oid relOid, CmdType operation, uint32 naffected)
+makeAnalyze(Oid relOid, CmdType operation, int32 naffected)
{
PgStat_StatTabEntry *tabentry;
TimestampTz now = GetCurrentTimestamp();
if (relOid == InvalidOid)
return;
+ if (naffected == 0)
+ /* return if there is not changes */
+ return;
+ else if (naffected < 0)
+ /* number if affected rows is unknown */
+ naffected = 0;
+
+ if (get_rel_relkind(relOid) != RELKIND_RELATION)
+ return;
+
tabentry = pgstat_fetch_stat_tabentry(relOid);
#if PG_VERSION_NUM >= 90000
#define changes_since_analyze(t) ((t)->n_live_tuples + (t)->n_dead_tuples - (t)->last_anl_tuples)
#endif
- if (
+ if (
tabentry == NULL /* a new table */ ||
(
/* do not analyze too often, if both stamps are exceeded the go */
)
)
{
+#if PG_VERSION_NUM < 90500
VacuumStmt vacstmt;
+#else
+ VacuumParams vacstmt;
+#endif
TimestampTz startStamp, endStamp;
+ memset(&startStamp, 0, sizeof(startStamp)); /* keep compiler quiet */
+
/*
* includeTables overwrites excludeTables
*/
default:
{
Relation rel;
- OnlyneAnalyzeTableType reltype;
+ OnlineAnalyzeTableType reltype;
rel = RelationIdGetRelation(relOid);
- reltype = (rel->rd_istemp || rel->rd_islocaltemp) ? OATT_TEMPORARY : OATT_PERSISTENT;
+ reltype =
+#if PG_VERSION_NUM >= 90100
+ (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+#else
+ (rel->rd_istemp || rel->rd_islocaltemp)
+#endif
+ ? OATT_TEMPORARY : OATT_PERSISTENT;
RelationClose(rel);
/*
break;
}
- vacstmt.type = T_VacuumStmt;
+ memset(&vacstmt, 0, sizeof(vacstmt));
+
vacstmt.freeze_min_age = -1;
vacstmt.freeze_table_age = -1; /* ??? */
+
+#if PG_VERSION_NUM < 90500
+ vacstmt.type = T_VacuumStmt;
vacstmt.relation = NULL;
vacstmt.va_cols = NIL;
-
#if PG_VERSION_NUM >= 90000
vacstmt.options = VACOPT_ANALYZE;
if (online_analyze_verbose)
vacstmt.analyze = true;
vacstmt.verbose = online_analyze_verbose;
#endif
+#else
+ vacstmt.multixact_freeze_min_age = -1;
+ vacstmt.multixact_freeze_table_age = -1;
+ vacstmt.log_min_duration = -1;
+#endif
if (online_analyze_verbose)
startStamp = GetCurrentTimestamp();
- analyze_rel(relOid, &vacstmt, GetAccessStrategy(BAS_VACUUM)
-#if (PG_VERSION_NUM < 90004) && (PG_VERSION_NUM >= 90000)
+ analyze_rel(relOid,
+#if PG_VERSION_NUM < 90500
+ &vacstmt
+#if PG_VERSION_NUM >= 90018
+ , true
+#endif
+ , GetAccessStrategy(BAS_VACUUM)
+#if (PG_VERSION_NUM >= 90000) && (PG_VERSION_NUM < 90004)
, true
+#endif
+#else
+ makeRangeVarFromOid(relOid), VACOPT_ANALYZE | ((online_analyze_verbose) ? VACOPT_VERBOSE : 0),
+ &vacstmt, NULL, true, GetAccessStrategy(BAS_VACUUM)
#endif
);
extern PGDLLIMPORT void onlineAnalyzeHooker(QueryDesc *queryDesc);
void
-onlineAnalyzeHooker(QueryDesc *queryDesc)
+onlineAnalyzeHooker(QueryDesc *queryDesc)
{
- uint32 naffected = 0;
+ uint32 naffected = -1;
if (queryDesc->estate)
- naffected = queryDesc->estate->es_processed;
+ naffected = queryDesc->estate->es_processed;
if (online_analyze_enable && queryDesc->plannedstmt &&
- (queryDesc->operation == CMD_INSERT ||
+ (queryDesc->operation == CMD_INSERT ||
queryDesc->operation == CMD_UPDATE ||
- queryDesc->operation == CMD_DELETE ||
- (queryDesc->operation == CMD_SELECT && queryDesc->plannedstmt->intoClause)))
+ queryDesc->operation == CMD_DELETE
+#if PG_VERSION_NUM < 90200
+ || (queryDesc->operation == CMD_SELECT && queryDesc->plannedstmt->intoClause)
+#endif
+ ))
{
- if (queryDesc->plannedstmt->intoClause)
+#if PG_VERSION_NUM < 90200
+ if (queryDesc->operation == CMD_SELECT)
{
Oid relOid = RangeVarGetRelid(queryDesc->plannedstmt->intoClause->rel, true);
makeAnalyze(relOid, queryDesc->operation, naffected);
}
- else if (queryDesc->plannedstmt->resultRelations &&
+ else
+#endif
+ if (queryDesc->plannedstmt->resultRelations &&
queryDesc->plannedstmt->rtable)
{
ListCell *l;
{
int n = lfirst_int(l);
RangeTblEntry *rte = list_nth(queryDesc->plannedstmt->rtable, n-1);
-
+
if (rte->rtekind == RTE_RELATION)
makeAnalyze(rte->relid, queryDesc->operation, naffected);
}
}
}
- if (oldhook)
- (*oldhook)(queryDesc);
+ if (oldExecutorEndHook)
+ oldExecutorEndHook(queryDesc);
else
standard_ExecutorEnd(queryDesc);
}
+#if PG_VERSION_NUM >= 90200
+static void
+onlineAnalyzeHookerUtility(Node *parsetree, const char *queryString,
+#if PG_VERSION_NUM >= 90300
+ ProcessUtilityContext context, ParamListInfo params,
+#else
+ ParamListInfo params, bool isTopLevel,
+#endif
+ DestReceiver *dest, char *completionTag) {
+ RangeVar *tblname = NULL;
+
+ if (IsA(parsetree, CreateTableAsStmt) && ((CreateTableAsStmt*)parsetree)->into)
+ tblname = (RangeVar*)copyObject(((CreateTableAsStmt*)parsetree)->into->rel);
+
+ if (oldProcessUtilityHook)
+ oldProcessUtilityHook(parsetree, queryString,
+#if PG_VERSION_NUM >= 90300
+ context, params,
+#else
+ params, isTopLevel,
+#endif
+ dest, completionTag);
+ else
+ standard_ProcessUtility(parsetree, queryString,
+#if PG_VERSION_NUM >= 90300
+ context, params,
+#else
+ params, isTopLevel,
+#endif
+ dest, completionTag);
+
+ if (tblname) {
+ Oid tblOid = RangeVarGetRelid(tblname, NoLock, true);
+
+ makeAnalyze(tblOid, CMD_INSERT, -1);
+ }
+}
+#endif
+
void _PG_init(void);
void
_PG_init(void)
{
- oldhook = ExecutorEnd_hook;
+ oldExecutorEndHook = ExecutorEnd_hook;
ExecutorEnd_hook = onlineAnalyzeHooker;
+#if PG_VERSION_NUM >= 90200
+ oldProcessUtilityHook = ProcessUtility_hook;
+
+ ProcessUtility_hook = onlineAnalyzeHookerUtility;
+#endif
+
+
DefineCustomBoolVariable(
"online_analyze.enable",
"Enable on-line analyze",
"online_analyze.min_interval",
"minimum time interval between analyze call (in milliseconds)",
"minimum time interval between analyze call (in milliseconds)",
- &online_analyze_scale_factor,
+ &online_analyze_min_interval,
#if PG_VERSION_NUM >= 80400
online_analyze_min_interval,
#endif
NULL
);
-DefineCustomEnumVariable(
+ DefineCustomEnumVariable(
"online_analyze.table_type",
- "Type(s) of table for onlyne analyze: all(default), persistent, temporary, none",
+ "Type(s) of table for online analyze: all(default), persistent, temporary, none",
NULL,
&online_analyze_table_type,
#if PG_VERSION_NUM >= 80400
void
_PG_fini(void)
{
- ExecutorEnd_hook = oldhook;
+ ExecutorEnd_hook = oldExecutorEndHook;
+#if PG_VERSION_NUM >= 90200
+ ProcessUtility_hook = oldProcessUtilityHook;
+#endif
if (excludeTables.tables)
free(excludeTables.tables);