From 7f4bd696f8162137762826478f450074df5b7939 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 7 Dec 2016 16:12:55 +0300
Subject: [PATCH 2/6] Add stats_form_tuple()

---
 src/backend/utils/adt/selfuncs.c | 55 ++++++++++++++++++++++++++++++++
 src/include/utils/selfuncs.h     | 22 +++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index d1dd049f1ae..f534e862079 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -7954,3 +7954,58 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
 
 	*indexPages = index->pages;
 }
+
+/*
+ * stats_form_tuple - Form pg_statistic tuple from StatsData.
+ *
+ * If 'data' parameter is NULL, form all-NULL tuple (nullfrac = 1.0).
+ */
+HeapTuple
+stats_form_tuple(StatsData *data)
+{
+	Relation	rel;
+	HeapTuple	tuple;
+	Datum		values[Natts_pg_statistic];
+	bool		nulls[Natts_pg_statistic];
+	int			i;
+
+	for (i = 0; i < Natts_pg_statistic; ++i)
+		nulls[i] = false;
+
+	values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(InvalidOid);
+	values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(0);
+	values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(false);
+	values[Anum_pg_statistic_stanullfrac - 1] =
+									Float4GetDatum(data ? data->nullfrac : 1.0);
+	values[Anum_pg_statistic_stawidth - 1] =
+									Int32GetDatum(data ? data->width : 0);
+	values[Anum_pg_statistic_stadistinct - 1] =
+									Float4GetDatum(data ? data->distinct : 0);
+
+	for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
+	{
+		StatsSlot *slot = data ? &data->slots[i] : NULL;
+
+		values[Anum_pg_statistic_stakind1 + i - 1] =
+								Int16GetDatum(slot ? slot->kind : 0);
+
+		values[Anum_pg_statistic_staop1 + i - 1] =
+					ObjectIdGetDatum(slot ? slot->opid : InvalidOid);
+
+		if (slot && DatumGetPointer(slot->numbers))
+			values[Anum_pg_statistic_stanumbers1 + i - 1] = slot->numbers;
+		else
+			nulls[Anum_pg_statistic_stanumbers1 + i - 1] = true;
+
+		if (slot && DatumGetPointer(slot->values))
+			values[Anum_pg_statistic_stavalues1 + i - 1] = slot->values;
+		else
+			nulls[Anum_pg_statistic_stavalues1 + i - 1] = true;
+	}
+
+	rel = table_open(StatisticRelationId, AccessShareLock);
+	tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+	table_close(rel, NoLock);
+
+	return tuple;
+}
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
index 8f3d73edfb2..49fc3d717b1 100644
--- a/src/include/utils/selfuncs.h
+++ b/src/include/utils/selfuncs.h
@@ -16,6 +16,7 @@
 #define SELFUNCS_H
 
 #include "access/htup.h"
+#include "catalog/pg_statistic.h"
 #include "fmgr.h"
 #include "nodes/pathnodes.h"
 
@@ -133,6 +134,24 @@ typedef struct
 	double		num_sa_scans;	/* # indexscans from ScalarArrayOpExprs */
 } GenericCosts;
 
+/* Single pg_statistic slot */
+typedef struct StatsSlot
+{
+	int16	kind;		/* stakindN: statistic kind (STATISTIC_KIND_XXX) */
+	Oid		opid;		/* staopN: associated operator, if needed */
+	Datum	numbers;	/* stanumbersN: float4 array of numbers */
+	Datum	values;		/* stavaluesN: anyarray of values */
+} StatsSlot;
+
+/* Deformed pg_statistic tuple */
+typedef struct StatsData
+{
+	float4		nullfrac;	/* stanullfrac: fraction of NULL values  */
+	float4		distinct;	/* stadistinct: number of distinct non-NULL values */
+	int32		width;		/* stawidth: average width in bytes of non-NULL values */
+	StatsSlot	slots[STATISTIC_NUM_SLOTS]; /* slots for different statistic types */
+} StatsData;
+
 /* Hooks for plugins to get control when we ask for stats */
 typedef bool (*get_relation_stats_hook_type) (PlannerInfo *root,
 											  RangeTblEntry *rte,
@@ -231,6 +250,9 @@ extern void genericcostestimate(PlannerInfo *root, IndexPath *path,
 								double loop_count,
 								GenericCosts *costs);
 
+extern HeapTuple stats_form_tuple(StatsData *data);
+
+
 /* Functions in array_selfuncs.c */
 
 extern Selectivity scalararraysel_containment(PlannerInfo *root,
-- 
2.25.1

