diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 4a2b6f0dae..88c635f82f 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1310,8 +1310,6 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
     If a table parameter value is set and the
     equivalent <literal>toast.</literal> parameter is not, the TOAST table
     will use the table's parameter value.
-    Specifying these parameters for partitioned tables is not supported,
-    but you may specify them for individual leaf partitions.
    </para>
 
    <variablelist>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 79430d2b7b..20183a96a4 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -108,7 +108,7 @@ static relopt_bool boolRelOpts[] =
 		{
 			"autovacuum_enabled",
 			"Enables autovacuum in this relation",
-			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_PARTITIONED,
 			ShareUpdateExclusiveLock
 		},
 		true
@@ -227,7 +227,7 @@ static relopt_int intRelOpts[] =
 		{
 			"autovacuum_analyze_threshold",
 			"Minimum number of tuple inserts, updates or deletes prior to analyze",
-			RELOPT_KIND_HEAP,
+			RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
 			ShareUpdateExclusiveLock
 		},
 		-1, 0, INT_MAX
@@ -379,7 +379,7 @@ static relopt_real realRelOpts[] =
 		{
 			"autovacuum_analyze_scale_factor",
 			"Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
-			RELOPT_KIND_HEAP,
+			RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
 			ShareUpdateExclusiveLock
 		},
 		-1, 0.0, 100.0
@@ -1586,13 +1586,12 @@ build_reloptions(Datum reloptions, bool validate,
 bytea *
 partitioned_table_reloptions(Datum reloptions, bool validate)
 {
+
 	/*
-	 * There are no options for partitioned tables yet, but this is able to do
-	 * some validation.
+	 * autovacuum_enabled, autovacuum_analyze_threshold and
+	 * autovacuum_analyze_scale_factor are supported for partitioned tables.
 	 */
-	return (bytea *) build_reloptions(reloptions, validate,
-									  RELOPT_KIND_PARTITIONED,
-									  0, NULL, 0);
+	return default_reloptions(reloptions, validate, RELOPT_KIND_PARTITIONED);
 }
 
 /*
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index f681aafcf9..161abb6450 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -584,7 +584,7 @@ CREATE VIEW pg_stat_all_tables AS
     FROM pg_class C LEFT JOIN
          pg_index I ON C.oid = I.indrelid
          LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
-    WHERE C.relkind IN ('r', 't', 'm')
+    WHERE C.relkind IN ('r', 't', 'm', 'p')
     GROUP BY C.oid, N.nspname, C.relname;
 
 CREATE VIEW pg_stat_xact_all_tables AS
@@ -604,7 +604,7 @@ CREATE VIEW pg_stat_xact_all_tables AS
     FROM pg_class C LEFT JOIN
          pg_index I ON C.oid = I.indrelid
          LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
-    WHERE C.relkind IN ('r', 't', 'm')
+    WHERE C.relkind IN ('r', 't', 'm', 'p')
     GROUP BY C.oid, N.nspname, C.relname;
 
 CREATE VIEW pg_stat_sys_tables AS
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index c4420ddd7f..df3d93ea5d 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -655,15 +655,14 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
 	}
 
 	/*
-	 * Report ANALYZE to the stats collector, too.  However, if doing
-	 * inherited stats we shouldn't report, because the stats collector only
-	 * tracks per-table stats.  Reset the changes_since_analyze counter only
-	 * if we analyzed all columns; otherwise, there is still work for
-	 * auto-analyze to do.
+	 * Report ANALYZE to the stats collector, too.  If the table is a
+	 * partition, report changes_since_analyze of its parent because
+	 * autovacuum process for partitioned tables needs it.  Reset the
+	 * changes_since_analyze counter only if we analyzed all columns;
+	 * otherwise, there is still work for auto-analyze to do.
 	 */
-	if (!inh)
-		pgstat_report_analyze(onerel, totalrows, totaldeadrows,
-							  (va_cols == NIL));
+	pgstat_report_analyze(onerel, totalrows, totaldeadrows,
+						  (va_cols == NIL));
 
 	/* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */
 	if (!(params->options & VACOPT_VACUUM))
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 6d1f28c327..7d0a5ce30d 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -75,6 +75,7 @@
 #include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_database.h"
+#include "catalog/pg_inherits.h"
 #include "commands/dbcommands.h"
 #include "commands/vacuum.h"
 #include "lib/ilist.h"
@@ -2031,11 +2032,11 @@ do_autovacuum(void)
 	 * Scan pg_class to determine which tables to vacuum.
 	 *
 	 * We do this in two passes: on the first one we collect the list of plain
-	 * relations and materialized views, and on the second one we collect
-	 * TOAST tables. The reason for doing the second pass is that during it we
-	 * want to use the main relation's pg_class.reloptions entry if the TOAST
-	 * table does not have any, and we cannot obtain it unless we know
-	 * beforehand what's the main table OID.
+	 * relations, materialized views and partitioned tables, and on the second
+	 * one we collect TOAST tables. The reason for doing the second pass is that
+	 * during it we want to use the main relation's pg_class.reloptions entry
+	 * if the TOAST table does not have any, and we cannot obtain it unless we
+	 * know beforehand what's the main table OID.
 	 *
 	 * We need to check TOAST tables separately because in cases with short,
 	 * wide tables there might be proportionally much more activity in the
@@ -2058,7 +2059,8 @@ do_autovacuum(void)
 		bool		wraparound;
 
 		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW)
+			classForm->relkind != RELKIND_MATVIEW &&
+			classForm->relkind != RELKIND_PARTITIONED_TABLE)
 			continue;
 
 		relid = classForm->oid;
@@ -2087,19 +2089,103 @@ do_autovacuum(void)
 			continue;
 		}
 
-		/* Fetch reloptions and the pgstat entry for this table */
-		relopts = extract_autovac_opts(tuple, pg_class_desc);
-		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
-											 shared, dbentry);
+		if (classForm->relkind == RELKIND_RELATION ||
+			classForm->relkind == RELKIND_MATVIEW)
+		{
+			/* Fetch reloptions and the pgstat entry for this table */
+			relopts = extract_autovac_opts(tuple, pg_class_desc);
+			tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
+												 shared, dbentry);
+
+			/* Check if it needs vacuum or analyze */
+			relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
+									  effective_multixact_freeze_max_age,
+									  &dovacuum, &doanalyze, &wraparound);
+
+			/* Relations that need work are added to table_oids */
+			if (dovacuum || doanalyze)
+				table_oids = lappend_oid(table_oids, relid);
+		}
+		else
+		{
+			/*
+			 * If the relation is a partitioned table, we check it using reltuples
+			 * added up childrens' and changes_since_analyze tracked by stats collector.
+			 * We check only auto analyze because partitioned tables don't need to vacuum.
+			 */
+			List     *tableOIDs;
+			ListCell *lc;
+			bool      av_enabled;
+			int       anl_base_thresh;
+			float4    all_reltuples = 0,
+			          anl_scale_factor,
+				      anlthresh,
+				      reltuples,
+				      anltuples;
+
+			/* Find all members of inheritance set taking AccessShareLock */
+			tableOIDs = find_all_inheritors(relid, AccessShareLock, NULL);
+
+			foreach(lc, tableOIDs)
+			{
+				Oid        childOID = lfirst_oid(lc);
+				HeapTuple  childtuple;
+				Form_pg_class childclassForm;
 
-		/* Check if it needs vacuum or analyze */
-		relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
-								  effective_multixact_freeze_max_age,
-								  &dovacuum, &doanalyze, &wraparound);
+				/* Ignore the parent table */
+				if (childOID == relid)
+					continue;
 
-		/* Relations that need work are added to table_oids */
-		if (dovacuum || doanalyze)
-			table_oids = lappend_oid(table_oids, relid);
+				childtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(childOID));
+				childclassForm = (Form_pg_class) GETSTRUCT(childtuple);
+
+				/* Skip foreign partitions */
+				if (childclassForm->relkind == RELKIND_FOREIGN_TABLE)
+					continue;
+
+				/* Sum up the child's reltuples for its parent table */
+				all_reltuples += childclassForm->reltuples;
+				elog(NOTICE, "[parent:%s] child%s has %.0f tuples", NameStr(classForm->relname),NameStr(childclassForm->relname), childclassForm->reltuples);
+			}
+
+
+			/* Fetch reloptions and the pgstat entry for the partitioned table */
+			relopts = extract_autovac_opts(tuple, pg_class_desc);
+			tabentry = get_pgstat_tabentry_relid(relid,
+												 classForm->relisshared,
+												 shared, dbentry);
+
+			/* Check if it needs auto analyze */
+			av_enabled = (relopts ? relopts->enabled : true);
+
+			if (av_enabled)
+			{
+				anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
+					? relopts->analyze_scale_factor
+					: autovacuum_anl_scale;
+
+				anl_base_thresh = (relopts && relopts->analyze_threshold >= 0)
+					? relopts->analyze_threshold
+					: autovacuum_anl_thresh;
+
+				elog(NOTICE, "[parent:%s] has %.0f tuples", NameStr(classForm->relname), all_reltuples);
+				if (PointerIsValid(tabentry))
+				{
+					reltuples = all_reltuples;
+					anltuples = tabentry->changes_since_analyze;
+					anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
+
+					elog(DEBUG3, "%s: anl: %.0f (threshold %.0f)",
+						 NameStr(classForm->relname),
+						 anltuples, anlthresh);
+
+					/* Determine if this table needs analyze. */
+					doanalyze = (anltuples > anlthresh);
+				}
+				if (doanalyze)
+					table_oids = lappend_oid(table_oids, relid);
+			}
+		}
 
 		/*
 		 * Remember TOAST associations for the second pass.  Note: we must do
@@ -2720,6 +2806,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
 
 	Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
 		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
+		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_PARTITIONED_TABLE ||
 		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
 
 	relopts = extractRelOptions(tup, pg_class_desc, NULL);
@@ -2793,33 +2880,105 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
 		return NULL;
 	classForm = (Form_pg_class) GETSTRUCT(classTup);
 
-	/*
-	 * Get the applicable reloptions.  If it is a TOAST table, try to get the
-	 * main table reloptions if the toast table itself doesn't have.
-	 */
-	avopts = extract_autovac_opts(classTup, pg_class_desc);
-	if (classForm->relkind == RELKIND_TOASTVALUE &&
-		avopts == NULL && table_toast_map != NULL)
+	if (classForm->relkind != RELKIND_PARTITIONED_TABLE)
 	{
-		av_relation *hentry;
-		bool		found;
+		/*
+		 * Get the applicable reloptions.  If it is a TOAST table, try to get the
+		 * main table reloptions if the toast table itself doesn't have.
+		 */
+		avopts = extract_autovac_opts(classTup, pg_class_desc);
+		if (classForm->relkind == RELKIND_TOASTVALUE &&
+			avopts == NULL && table_toast_map != NULL)
+		{
+			av_relation *hentry;
+			bool		found;
 
-		hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
-		if (found && hentry->ar_hasrelopts)
-			avopts = &hentry->ar_reloptions;
+			hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
+			if (found && hentry->ar_hasrelopts)
+				avopts = &hentry->ar_reloptions;
+		}
+
+		/* fetch the pgstat table entry */
+		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
+											 shared, dbentry);
+
+		relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+								  effective_multixact_freeze_max_age,
+								  &dovacuum, &doanalyze, &wraparound);
+
+		/* ignore ANALYZE for toast tables */
+		if (classForm->relkind == RELKIND_TOASTVALUE)
+			doanalyze = false;
 	}
+	else
+	{
+		List     *tableOIDs;
+		ListCell *lc;
+		bool      av_enabled;
+		int       anl_base_thresh;
+		float4    all_reltuples,
+			      anl_scale_factor,
+			      anlthresh,
+			      reltuples,
+			      anltuples;
+
+		/* Find all members of inheritance set taking AccessShareLock */
+		tableOIDs = find_all_inheritors(relid, AccessShareLock, NULL);
+
+		foreach(lc, tableOIDs)
+		{
+			Oid       childOID = lfirst_oid(lc);
+			HeapTuple childtuple;
+			Form_pg_class childclassForm;
 
-	/* fetch the pgstat table entry */
-	tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
-										 shared, dbentry);
+			/* Ignore the parent table */
+			if (childOID == relid)
+				continue;
+
+			childtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(childOID));
+			childclassForm = (Form_pg_class) GETSTRUCT(childtuple);
 
-	relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
-							  effective_multixact_freeze_max_age,
-							  &dovacuum, &doanalyze, &wraparound);
+			/* Skip foreign partitions */
+			if (childclassForm->relkind == RELKIND_FOREIGN_TABLE)
+				continue;
+
+			/* Sum up the child's reltuples for the partitioned table */
+			all_reltuples += childclassForm->reltuples;
+		}
 
-	/* ignore ANALYZE for toast tables */
-	if (classForm->relkind == RELKIND_TOASTVALUE)
-		doanalyze = false;
+		/* Fetch reloptions and the pgstat entry for the partitioned table */
+		avopts = extract_autovac_opts(classTup, pg_class_desc);
+		tabentry = get_pgstat_tabentry_relid(relid,
+											 classForm->relisshared,
+											 shared, dbentry);
+
+		/* Check if it needs auto analyze */
+		av_enabled = (avopts ? avopts->enabled : true);
+
+		if (av_enabled)
+		{
+			anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0)
+				? avopts->analyze_scale_factor
+				: autovacuum_anl_scale;
+
+			anl_base_thresh = (avopts && avopts->analyze_threshold >= 0)
+				? avopts->analyze_threshold
+				: autovacuum_anl_thresh;
+
+			if (PointerIsValid(tabentry))
+			{
+				reltuples = all_reltuples;
+				anltuples = tabentry->changes_since_analyze;
+				anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
+
+				elog(DEBUG3, "%s: anl: %.0f (threshold %.0f)",
+					 NameStr(classForm->relname),
+					 anltuples, anlthresh);
+
+				doanalyze = (anltuples > anlthresh);
+			}
+		}
+	}
 
 	/* OK, it needs something done */
 	if (doanalyze || dovacuum)
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 59dc4f31ab..1933da145a 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -38,6 +38,7 @@
 #include "access/transam.h"
 #include "access/twophase_rmgr.h"
 #include "access/xact.h"
+#include "catalog/partition.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_proc.h"
 #include "common/ip.h"
@@ -67,6 +68,7 @@
 #include "utils/ps_status.h"
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
+#include "utils/syscache.h"
 #include "utils/timestamp.h"
 
 /* ----------
@@ -322,6 +324,7 @@ static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, in
 static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len);
 static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
 static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
+static void pgstat_recv_partanalyze(PgStat_MsgPartAnalyze *msg, int len);
 static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len);
 static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len);
 static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
@@ -1463,6 +1466,32 @@ pgstat_report_analyze(Relation rel,
 		deadtuples = Max(deadtuples, 0);
 	}
 
+	/*
+	 * If the table is a leaf partition, tell the stats collector its parent's
+	 * changes_since_analyze for auto analyze
+	 */
+	if (rel->rd_rel->relispartition &&
+		!(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
+	{
+		Oid      parentoid;
+		Relation parentrel;
+		PgStat_StatDBEntry *dbentry;
+		PgStat_StatTabEntry *tabentry;
+
+		/* Get its parent table's Oid and relation */
+		parentoid = get_partition_parent(RelationGetRelid(rel));
+		parentrel = table_open(parentoid, AccessShareLock);
+
+		/* Fetch the pgstat for this table */
+		dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId);
+		tabentry = pgstat_get_tab_entry(dbentry, RelationGetRelid(rel), true);
+
+		/* Report changes_since_analyze to the stats collector */
+		pgstat_report_partanalyze(parentrel, tabentry->changes_since_analyze);
+
+		table_close(parentrel, AccessShareLock);
+	}
+
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE);
 	msg.m_databaseid = rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId;
 	msg.m_tableoid = RelationGetRelid(rel);
@@ -1475,6 +1504,49 @@ pgstat_report_analyze(Relation rel,
 }
 
 /* --------
+ * pgstat_report_partanalyze() -
+ *
+ *	Tell the collector about the parent table of which partition just analyzed.
+ *
+ * Caller must provide a child's changes_since_analyze as a parents.
+ * --------
+ */
+void
+pgstat_report_partanalyze(Relation rel, PgStat_Counter changes_tuples)
+{
+	PgStat_MsgPartAnalyze msg;
+
+	if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts)
+		return;
+
+	/*
+	 * If the partitioned table is also a partition, tell the stats collector
+	 * its parent's changes_since_analyze for auto analyze
+	 */
+	if (rel->rd_rel->relispartition)
+	{
+		Oid      parentoid;
+		Relation parentrel;
+		
+		/* Get its parent table's Oid and relation */
+		parentoid = get_partition_parent(RelationGetRelid(rel));
+		parentrel = table_open(parentoid, AccessShareLock);
+
+		/* Report changes_since_analyze to the stats collector */
+		pgstat_report_partanalyze(parentrel, changes_tuples);
+
+		table_close(parentrel, AccessShareLock);
+	}
+
+	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_PARTANALYZE);
+	msg.m_databaseid = rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId;
+	msg.m_tableoid = RelationGetRelid(rel);
+	msg.m_changes_tuples = changes_tuples;
+	pgstat_send(&msg, sizeof(msg));
+}
+
+
+/* --------
  * pgstat_report_recovery_conflict() -
  *
  *	Tell the collector about a Hot Standby recovery conflict.
@@ -1749,6 +1821,7 @@ pgstat_initstats(Relation rel)
 	/* We only count stats for things that have storage */
 	if (!(relkind == RELKIND_RELATION ||
 		  relkind == RELKIND_MATVIEW ||
+		  relkind == RELKIND_PARTITIONED_TABLE ||
 		  relkind == RELKIND_INDEX ||
 		  relkind == RELKIND_TOASTVALUE ||
 		  relkind == RELKIND_SEQUENCE))
@@ -4592,6 +4665,10 @@ PgstatCollectorMain(int argc, char *argv[])
 					pgstat_recv_analyze(&msg.msg_analyze, len);
 					break;
 
+				case PGSTAT_MTYPE_PARTANALYZE:
+					pgstat_recv_partanalyze(&msg.msg_partanalyze, len);
+					break;
+
 				case PGSTAT_MTYPE_ARCHIVER:
 					pgstat_recv_archiver(&msg.msg_archiver, len);
 					break;
@@ -6239,6 +6316,18 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
 	}
 }
 
+static void
+pgstat_recv_partanalyze(PgStat_MsgPartAnalyze *msg, int len)
+{
+	PgStat_StatDBEntry *dbentry;
+	PgStat_StatTabEntry *tabentry;
+
+	dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
+
+	tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true);
+
+	tabentry->changes_since_analyze += msg->m_changes_tuples;
+}
 
 /* ----------
  * pgstat_recv_archiver() -
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 3a65a51696..590885d7e8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -57,6 +57,7 @@ typedef enum StatMsgType
 	PGSTAT_MTYPE_AUTOVAC_START,
 	PGSTAT_MTYPE_VACUUM,
 	PGSTAT_MTYPE_ANALYZE,
+	PGSTAT_MTYPE_PARTANALYZE,
 	PGSTAT_MTYPE_ARCHIVER,
 	PGSTAT_MTYPE_BGWRITER,
 	PGSTAT_MTYPE_FUNCSTAT,
@@ -389,6 +390,18 @@ typedef struct PgStat_MsgAnalyze
 	PgStat_Counter m_dead_tuples;
 } PgStat_MsgAnalyze;
 
+/* ----------
+ * PgStat_MsgPartAnalyze		Sent by the backend or autovacuum daemon
+ *                              after ANALYZE for partitioned tables
+ * ----------
+ */
+typedef struct PgStat_MsgPartAnalyze
+{
+	PgStat_MsgHdr m_hdr;
+	Oid			m_databaseid;
+	Oid			m_tableoid;
+	PgStat_Counter m_changes_tuples;
+} PgStat_MsgPartAnalyze;
 
 /* ----------
  * PgStat_MsgArchiver			Sent by the archiver to update statistics.
@@ -562,6 +575,7 @@ typedef union PgStat_Msg
 	PgStat_MsgAutovacStart msg_autovacuum_start;
 	PgStat_MsgVacuum msg_vacuum;
 	PgStat_MsgAnalyze msg_analyze;
+	PgStat_MsgPartAnalyze msg_partanalyze;
 	PgStat_MsgArchiver msg_archiver;
 	PgStat_MsgBgWriter msg_bgwriter;
 	PgStat_MsgFuncstat msg_funcstat;
@@ -1267,7 +1281,7 @@ extern void pgstat_report_vacuum(Oid tableoid, bool shared,
 extern void pgstat_report_analyze(Relation rel,
 								  PgStat_Counter livetuples, PgStat_Counter deadtuples,
 								  bool resetcounter);
-
+extern void pgstat_report_partanalyze(Relation rel, PgStat_Counter changes_tuples);
 extern void pgstat_report_recovery_conflict(int reason);
 extern void pgstat_report_deadlock(void);
 extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 634f8256f7..7e9f6de9cb 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1789,7 +1789,7 @@ pg_stat_all_tables| SELECT c.oid AS relid,
    FROM ((pg_class c
      LEFT JOIN pg_index i ON ((c.oid = i.indrelid)))
      LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
-  WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]))
+  WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char", 'p'::"char"]))
   GROUP BY c.oid, n.nspname, c.relname;
 pg_stat_archiver| SELECT s.archived_count,
     s.last_archived_wal,
@@ -2117,7 +2117,7 @@ pg_stat_xact_all_tables| SELECT c.oid AS relid,
    FROM ((pg_class c
      LEFT JOIN pg_index i ON ((c.oid = i.indrelid)))
      LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
-  WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]))
+  WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char", 'p'::"char"]))
   GROUP BY c.oid, n.nspname, c.relname;
 pg_stat_xact_sys_tables| SELECT pg_stat_xact_all_tables.relid,
     pg_stat_xact_all_tables.schemaname,
