cross-column-v10.patch
text/plain
Filename: cross-column-v10.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v10
| File | + | − |
|---|---|---|
| src/backend/catalog/Makefile | 2 | 2 |
| src/backend/commands/indexcmds.c | 266 | 0 |
| src/backend/executor/nodeHash.c | 1 | 1 |
| src/backend/nodes/copyfuncs.c | 16 | 0 |
| src/backend/nodes/equalfuncs.c | 15 | 0 |
| src/backend/optimizer/path/clausesel.c | 430 | 0 |
| src/backend/parser/gram.y | 78 | 5 |
| src/backend/parser/parse_utilcmd.c | 176 | 0 |
| src/backend/tcop/utility.c | 32 | 0 |
| src/backend/tsearch/ts_selfuncs.c | 1 | 1 |
| src/backend/utils/adt/selfuncs.c | 113 | 23 |
| src/backend/utils/cache/catcache.c | 1 | 0 |
| src/backend/utils/cache/lsyscache.c | 68 | 8 |
| src/backend/utils/cache/syscache.c | 12 | 0 |
| src/include/catalog/indexing.h | 7 | 0 |
| src/include/catalog/pg_statistic2.h | 265 | 0 |
| src/include/catalog/pg_statistic3.h | 265 | 0 |
| src/include/commands/defrem.h | 1 | 0 |
| src/include/nodes/nodes.h | 1 | 0 |
| src/include/nodes/parsenodes.h | 13 | 0 |
| src/include/parser/kwlist.h | 1 | 0 |
| src/include/parser/parse_utilcmd.h | 5 | 0 |
| src/include/utils/lsyscache.h | 3 | 1 |
| src/include/utils/selfuncs.h | 8 | 2 |
| src/include/utils/syscache.h | 1 | 0 |
| src/test/regress/expected/sanity_check.out | 3 | 1 |
diff -dcrpN postgresql.orig/src/backend/catalog/Makefile postgresql/src/backend/catalog/Makefile
*** postgresql.orig/src/backend/catalog/Makefile 2011-02-22 18:51:42.675518441 +0100
--- postgresql/src/backend/catalog/Makefile 2011-04-28 14:21:14.694179328 +0200
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
*** 31,38 ****
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \
! pg_statistic.h pg_rewrite.h pg_trigger.h pg_description.h \
! pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
--- 31,38 ----
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \
! pg_statistic.h pg_statistic2.h pg_statistic3.h pg_rewrite.h pg_trigger.h \
! pg_description.h pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
diff -dcrpN postgresql.orig/src/backend/commands/indexcmds.c postgresql/src/backend/commands/indexcmds.c
*** postgresql.orig/src/backend/commands/indexcmds.c 2011-04-26 09:54:04.012362009 +0200
--- postgresql/src/backend/commands/indexcmds.c 2011-04-28 14:21:14.697179127 +0200
***************
*** 26,32 ****
--- 26,35 ----
#include "catalog/indexing.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
+ #include "catalog/pg_statistic2.h"
+ #include "catalog/pg_statistic3.h"
#include "catalog/pg_tablespace.h"
+ #include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
***************
*** 36,41 ****
--- 39,45 ----
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planner.h"
+ #include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
*************** ReindexDatabase(const char *databaseName
*** 1693,1695 ****
--- 1697,1961 ----
MemoryContextDelete(private_context);
}
+
+ /*
+ * DoCrossColStat
+ * Add or remove one row in pg_statistic2
+ */
+ static void
+ DoCrossColStat(ExtraStatStmt *stmt)
+ {
+ Oid relId;
+ Relation rel;
+ ListCell *l;
+ int len, i, j;
+ bool differ = false;
+ AttrNumber *attnums;
+ AttrNumber *sorted_attnums;
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+ Datum *datum_attnums;
+ ArrayType *arr_attnums;
+ ScanKeyData scanKey[2];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+ Datum values[Natts_pg_statistic2];
+ bool nulls[Natts_pg_statistic2];
+
+ relId = RangeVarGetRelid(stmt->relation, false);
+
+ len = list_length(stmt->columns);
+ if (len < 2)
+ elog(ERROR, "cross column statistics need at least two columns");
+
+ attnums = (int2 *)palloc(len * sizeof(AttrNumber));
+ sorted_attnums = (int2 *)palloc(len * sizeof(AttrNumber));
+ datum_attnums = (Datum *)palloc(len * sizeof(Datum));
+
+ i = 0;
+ foreach(l, stmt->columns)
+ {
+ Node *node = (Node *) lfirst(l);
+ Var *var;
+
+ if (!IsA(node, Var))
+ elog(ERROR, "not a column reference");
+
+ var = (Var *) node;
+
+ if (var->varattno == 0)
+ elog(ERROR, "row expansion via \"*\" is not supported here");
+
+ attnums[i++] = var->varattno;
+ }
+
+ for (i = 0; i < len; i++)
+ sorted_attnums[i] = attnums[i];
+ for (i = 0; i < len - 1; i++)
+ for (j = i+1; j < len; j++)
+ if (sorted_attnums[i] > sorted_attnums[j])
+ {
+ AttrNumber tmp = sorted_attnums[i];
+
+ sorted_attnums[i] = sorted_attnums[j];
+ sorted_attnums[j] = tmp;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ if (!differ && attnums[i] != sorted_attnums[i])
+ differ = true;
+
+ if ((i < len - 1) && sorted_attnums[i] == sorted_attnums[i+1])
+ elog(ERROR, "column list must contain every column exactly once");
+
+ datum_attnums[i] = Int16GetDatum(sorted_attnums[i]);
+ }
+
+ if (differ)
+ elog(WARNING, "the column list was reordered in the order of table attributes");
+
+ get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign);
+ arr_attnums = construct_array(datum_attnums, len,
+ INT2OID, typlen, typbyval, typalign);
+
+ rel = heap_open(Statistic2RelationId, RowExclusiveLock);
+
+ /*
+ * There's no syscache for pg_statistic2,
+ * arrays aren't supported there as search keys.
+ * We need to do the hard way.
+ */
+ ScanKeyInit(&scanKey[0],
+ Anum_pg_statistic2_sta2relid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relId));
+ ScanKeyInit(&scanKey[1],
+ Anum_pg_statistic2_sta2attnums,
+ BTEqualStrategyNumber, F_ARRAY_EQ,
+ PointerGetDatum(arr_attnums));
+
+ scan = systable_beginscan(rel, Statistic2RelidAttnumsInhIndexId, true,
+ SnapshotNow, 2, scanKey);
+
+ tuple = systable_getnext(scan);
+
+ if (stmt->create)
+ {
+ if (HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ elog(ERROR, "pg_statistic2 entry already exists for this table and set of columns");
+ }
+ systable_endscan(scan);
+
+ for (i = 0; i < Natts_pg_statistic2; i++)
+ nulls[i] = TRUE;
+
+ values[Anum_pg_statistic2_sta2relid - 1] = ObjectIdGetDatum(relId);
+ nulls[Anum_pg_statistic2_sta2relid - 1] = FALSE;
+
+ values[Anum_pg_statistic2_sta2attnums - 1] = PointerGetDatum(arr_attnums);
+ nulls[Anum_pg_statistic2_sta2attnums - 1] = FALSE;
+
+ values[Anum_pg_statistic2_sta2inherit - 1] = BoolGetDatum(FALSE);
+ nulls[Anum_pg_statistic2_sta2inherit - 1] = FALSE;
+
+ tupDesc = RelationGetDescr(rel);
+
+ tuple = heap_form_tuple(tupDesc, values, nulls);
+
+ simple_heap_insert(rel, tuple);
+
+ CatalogUpdateIndexes(rel, tuple);
+ }
+ else
+ {
+ if (!HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ elog(ERROR, "pg_statistic2 entry doesn't exist for this table and set of columns");
+ }
+
+ simple_heap_delete(rel, &tuple->t_self);
+
+ systable_endscan(scan);
+ }
+
+ relation_close(rel, NoLock);
+ }
+
+ /*
+ * DoExprColStat
+ * Add or remove one row in pg_statistic3
+ */
+ static void
+ DoExprStat(ExtraStatStmt *stmt)
+ {
+ Oid relId;
+ Relation rel;
+ int i;
+ char *exprbin;
+ Datum exprbindatum;
+ ScanKeyData scanKey[2];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+ Datum values[Natts_pg_statistic3];
+ bool nulls[Natts_pg_statistic3];
+
+ if (IsA(stmt->expr, Var) || IsA(stmt->expr, ColumnRef))
+ elog(ERROR, "single column are covered by basic statistics");
+
+ relId = RangeVarGetRelid(stmt->relation, false);
+
+ rel = heap_open(Statistic3RelationId, RowExclusiveLock);
+
+ exprbin = nodeToString(stmt->expr);
+ exprbindatum = CStringGetTextDatum(exprbin);
+
+ /*
+ * There's no syscache for pg_statistic3,
+ * arrays aren't supported there as search keys.
+ * We need to do the hard way.
+ */
+ ScanKeyInit(&scanKey[0],
+ Anum_pg_statistic3_sta3relid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relId));
+ ScanKeyInit(&scanKey[1],
+ Anum_pg_statistic3_sta3expr,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ exprbindatum);
+
+ scan = systable_beginscan(rel, Statistic3RelidExprInhIndexId, true,
+ SnapshotNow, 2, scanKey);
+
+ tuple = systable_getnext(scan);
+
+ if (stmt->create)
+ {
+ if (HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ elog(ERROR, "pg_statistic3 entry already exists for this table and expression");
+ }
+ systable_endscan(scan);
+
+ if (!contain_var_clause(stmt->expr))
+ elog(ERROR, "constant expressions are not interesting");
+
+ for (i = 0; i < Natts_pg_statistic3; i++)
+ nulls[i] = TRUE;
+
+ values[Anum_pg_statistic3_sta3relid - 1] = ObjectIdGetDatum(relId);
+ nulls[Anum_pg_statistic3_sta3relid - 1] = FALSE;
+
+ values[Anum_pg_statistic3_sta3expr - 1] = exprbindatum;
+ nulls[Anum_pg_statistic3_sta3expr - 1] = FALSE;
+
+ values[Anum_pg_statistic3_sta3inherit - 1] = BoolGetDatum(FALSE);
+ nulls[Anum_pg_statistic3_sta3inherit - 1] = FALSE;
+
+ tupDesc = RelationGetDescr(rel);
+
+ tuple = heap_form_tuple(tupDesc, values, nulls);
+
+ simple_heap_insert(rel, tuple);
+
+ CatalogUpdateIndexes(rel, tuple);
+ }
+ else
+ {
+ if (!HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ elog(ERROR, "pg_statistic3 entry doesn't exist for this table and expression");
+ }
+
+ simple_heap_delete(rel, &tuple->t_self);
+
+ systable_endscan(scan);
+ }
+
+ pfree(exprbin);
+ pfree(DatumGetPointer(exprbindatum));
+
+ relation_close(rel, NoLock);
+ }
+
+ /*
+ * ExtraColStat
+ * Add or remove one entry in pg_statistics2 or pg_statistic3
+ */
+ void ExtraStatistics(ExtraStatStmt *stmt)
+ {
+ if (list_length(stmt->columns) > 0)
+ DoCrossColStat(stmt);
+ else if (stmt->expr != NULL)
+ DoExprStat(stmt);
+ else
+ elog(ERROR, "internal error in ExtraStatistics");
+ }
diff -dcrpN postgresql.orig/src/backend/executor/nodeHash.c postgresql/src/backend/executor/nodeHash.c
*** postgresql.orig/src/backend/executor/nodeHash.c 2011-04-11 15:36:27.096816773 +0200
--- postgresql/src/backend/executor/nodeHash.c 2011-04-28 14:21:14.700178924 +0200
*************** ExecHashBuildSkewHash(HashJoinTable hash
*** 1144,1150 ****
if (!HeapTupleIsValid(statsTuple))
return;
! if (get_attstatsslot(statsTuple, node->skewColType, node->skewColTypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
&values, &nvalues,
--- 1144,1150 ----
if (!HeapTupleIsValid(statsTuple))
return;
! if (get_attstatsslot(statsTuple, STAT_VARIABLE, node->skewColType, node->skewColTypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
&values, &nvalues,
diff -dcrpN postgresql.orig/src/backend/nodes/copyfuncs.c postgresql/src/backend/nodes/copyfuncs.c
*** postgresql.orig/src/backend/nodes/copyfuncs.c 2011-04-19 09:37:54.828715621 +0200
--- postgresql/src/backend/nodes/copyfuncs.c 2011-04-28 14:21:14.704178653 +0200
*************** _copyCreateForeignTableStmt(CreateForeig
*** 3458,3463 ****
--- 3458,3476 ----
return newnode;
}
+ static ExtraStatStmt *
+ _copyExtraStatStmt(ExtraStatStmt *from)
+ {
+ ExtraStatStmt *newnode = makeNode(ExtraStatStmt);
+
+ COPY_SCALAR_FIELD(create);
+ newnode->relation = _copyRangeVar(from->relation);
+ COPY_NODE_FIELD(columns);
+ COPY_NODE_FIELD(expr);
+
+ return newnode;
+ }
+
static CreateTrigStmt *
_copyCreateTrigStmt(CreateTrigStmt *from)
{
*************** copyObject(void *from)
*** 4377,4382 ****
--- 4390,4398 ----
case T_CreateForeignTableStmt:
retval = _copyCreateForeignTableStmt(from);
break;
+ case T_ExtraStatStmt:
+ retval = _copyExtraStatStmt(from);
+ break;
case T_CreateTrigStmt:
retval = _copyCreateTrigStmt(from);
break;
diff -dcrpN postgresql.orig/src/backend/nodes/equalfuncs.c postgresql/src/backend/nodes/equalfuncs.c
*** postgresql.orig/src/backend/nodes/equalfuncs.c 2011-04-19 09:37:54.829715550 +0200
--- postgresql/src/backend/nodes/equalfuncs.c 2011-04-28 14:21:14.707178453 +0200
*************** _equalCreateForeignTableStmt(CreateForei
*** 1795,1800 ****
--- 1795,1812 ----
}
static bool
+ _equalExtraStatStmt(ExtraStatStmt *a, ExtraStatStmt *b)
+ {
+ COMPARE_SCALAR_FIELD(create);
+ if (!_equalRangeVar(a->relation, b->relation))
+ return FALSE;
+ COMPARE_NODE_FIELD(columns);
+ COMPARE_NODE_FIELD(expr);
+
+ return true;
+ }
+
+ static bool
_equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
{
COMPARE_STRING_FIELD(trigname);
*************** equal(void *a, void *b)
*** 2930,2935 ****
--- 2942,2950 ----
case T_CreateForeignTableStmt:
retval = _equalCreateForeignTableStmt(a, b);
break;
+ case T_ExtraStatStmt:
+ retval = _equalExtraStatStmt(a, b);
+ break;
case T_CreateTrigStmt:
retval = _equalCreateTrigStmt(a, b);
break;
diff -dcrpN postgresql.orig/src/backend/optimizer/path/clausesel.c postgresql/src/backend/optimizer/path/clausesel.c
*** postgresql.orig/src/backend/optimizer/path/clausesel.c 2011-01-04 15:13:15.940560845 +0100
--- postgresql/src/backend/optimizer/path/clausesel.c 2011-04-28 14:21:14.720177575 +0200
***************
*** 13,29 ****
--- 13,40 ----
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+ #include "postgres_ext.h"
+ #include "access/skey.h"
+ #include "access/relscan.h"
+ #include "catalog/indexing.h"
#include "catalog/pg_operator.h"
+ #include "catalog/pg_statistic2.h"
+ #include "catalog/pg_statistic3.h"
+ #include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
+ #include "nodes/pg_list.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
+ #include "optimizer/var.h"
#include "parser/parsetree.h"
+ #include "utils/array.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/selfuncs.h"
+ #include "utils/tqual.h"
/*
*************** typedef struct RangeQueryClause
*** 34,39 ****
--- 45,51 ----
{
struct RangeQueryClause *next; /* next in linked list */
Node *var; /* The common variable of the clauses */
+ AttrNumber varattno; /* for finding cross-column statistics */
bool have_lobound; /* found a low-bound clause yet? */
bool have_hibound; /* found a high-bound clause yet? */
Selectivity lobound; /* Selectivity of a var > something clause */
*************** typedef struct RangeQueryClause
*** 43,48 ****
--- 55,75 ----
static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
bool varonleft, bool isLTsel, Selectivity s2);
+ typedef struct CrossColumnClause
+ {
+ struct CrossColumnClause *next;
+ Node *var;
+ AttrNumber varattno;
+ Node *expr;
+ Selectivity sel;
+ } CrossColumnClause;
+
+ static void addXCClause(CrossColumnClause **xclist, Node *clause,
+ bool varonleft, Selectivity s2);
+
+ static bool crosscolumn_selectivity(Oid relId,
+ CrossColumnClause **xcnext, RangeQueryClause **rqlist,
+ Selectivity *result_sel);
/****************************************************************************
* ROUTINES TO COMPUTE SELECTIVITIES
*************** clauselist_selectivity(PlannerInfo *root
*** 99,106 ****
--- 126,138 ----
{
Selectivity s1 = 1.0;
RangeQueryClause *rqlist = NULL;
+ CrossColumnClause *xclist = NULL;
+ Oid relId = InvalidOid;
+ bool onerel = false;
ListCell *l;
+ // elog(NOTICE, "clauselist_selectivity varRelid %d, list length %d", varRelid, list_length(clauses));
+
/*
* If there's exactly one clause, then no use in trying to match up pairs,
* so just go directly to clause_selectivity().
*************** clauselist_selectivity(PlannerInfo *root
*** 162,167 ****
--- 194,215 ----
(varonleft = false,
is_pseudo_constant_clause_relids(linitial(expr->args),
rinfo->left_relids)));
+ if (ok)
+ {
+ int relid;
+ Oid tmprelId;
+
+ relid = bms_singleton_member(rinfo->clause_relids);
+ tmprelId = root->simple_rte_array[relid]->relid;
+
+ if (!OidIsValid(relId))
+ {
+ onerel = true;
+ relId = tmprelId;
+ }
+ else if (relId != tmprelId)
+ onerel = false;
+ }
}
else
{
*************** clauselist_selectivity(PlannerInfo *root
*** 169,174 ****
--- 217,241 ----
(is_pseudo_constant_clause(lsecond(expr->args)) ||
(varonleft = false,
is_pseudo_constant_clause(linitial(expr->args))));
+ if (ok)
+ {
+ Relids relids;
+ int relid;
+ Oid tmprelId;
+
+ relids = pull_varnos(clause);
+ relid = bms_singleton_member(relids);
+ tmprelId = root->simple_rte_array[relid]->relid;
+ bms_free(relids);
+
+ if (!OidIsValid(relId))
+ {
+ onerel = true;
+ relId = tmprelId;
+ }
+ else if (relId != tmprelId)
+ onerel = false;
+ }
}
if (ok)
*************** clauselist_selectivity(PlannerInfo *root
*** 188,193 ****
--- 255,264 ----
addRangeClause(&rqlist, clause,
varonleft, false, s2);
break;
+ case F_EQSEL:
+ addXCClause(&xclist, clause,
+ varonleft, s2);
+ break;
default:
/* Just merge the selectivity in generically */
s1 = s1 * s2;
*************** clauselist_selectivity(PlannerInfo *root
*** 202,207 ****
--- 273,299 ----
}
/*
+ * Scan xclist and rqlist recursively and filter out
+ * all possible cross-column selectivities.
+ */
+ if (onerel)
+ crosscolumn_selectivity(relId, &xclist, &rqlist, &s1);
+
+ /*
+ * Free the cross-column clauses
+ */
+ while (xclist != NULL)
+ {
+ CrossColumnClause *xcnext;
+
+ s1 = s1 * xclist->sel;
+
+ xcnext = xclist->next;
+ pfree(xclist);
+ xclist = xcnext;
+ }
+
+ /*
* Now scan the rangequery pair list.
*/
while (rqlist != NULL)
*************** clauselist_selectivity(PlannerInfo *root
*** 279,284 ****
--- 371,392 ----
return s1;
}
+ static AttrNumber
+ var_get_attno(Node *clause)
+ {
+ Var *var;
+
+ if (IsA(clause, Var))
+ {
+ var = (Var *)clause;
+ // elog(NOTICE, "var_get_attno varattno %d", var->varattno);
+ return var->varattno;
+ }
+
+ // elog(NOTICE, "var_get_attno default 0");
+ return 0;
+ }
+
/*
* addRangeClause --- add a new range clause for clauselist_selectivity
*
*************** addRangeClause(RangeQueryClause **rqlist
*** 358,363 ****
--- 466,473 ----
/* No matching var found, so make a new clause-pair data structure */
rqelem = (RangeQueryClause *) palloc(sizeof(RangeQueryClause));
rqelem->var = var;
+ rqelem->varattno = var_get_attno(var);
+
if (is_lobound)
{
rqelem->have_lobound = true;
*************** addRangeClause(RangeQueryClause **rqlist
*** 375,380 ****
--- 485,522 ----
}
/*
+ * addXCClause - add a new clause to the list of clauses for cross-column stats inspection
+ *
+ */
+ static void
+ addXCClause(CrossColumnClause **xclist, Node *clause,
+ bool varonleft, Selectivity s)
+ {
+ CrossColumnClause *xcelem;
+ Node *var;
+ Node *expr;
+
+ if (varonleft)
+ {
+ var = get_leftop((Expr *) clause);
+ expr = get_rightop((Expr *) clause);
+ }
+ else
+ {
+ var = get_rightop((Expr *) clause);
+ expr = get_leftop((Expr *) clause);
+ }
+
+ xcelem = (CrossColumnClause *) palloc(sizeof(CrossColumnClause));
+ xcelem->var = var;
+ xcelem->varattno = var_get_attno(var);
+ xcelem->expr = expr;
+ xcelem->sel = s;
+ xcelem->next = *xclist;
+ *xclist = xcelem;
+ }
+
+ /*
* bms_is_subset_singleton
*
* Same result as bms_is_subset(s, bms_make_singleton(x)),
*************** clause_selectivity(PlannerInfo *root,
*** 499,504 ****
--- 641,648 ----
{
rinfo = (RestrictInfo *) clause;
+ // elog(NOTICE, "RestrictInfo, %s", nodeToString(rinfo->clause));
+
/*
* If the clause is marked pseudoconstant, then it will be used as a
* gating qual and should not affect selectivity estimates; hence
*************** clause_selectivity(PlannerInfo *root,
*** 779,781 ****
--- 923,1211 ----
return s1;
}
+
+ static bool
+ has_xcol_selectivity(Oid relId, int natts, AttrNumber *attnums, Selectivity *result_sel)
+ {
+ Relation rel;
+ Datum *datums = (Datum *)palloc(natts * sizeof(Datum));
+ ArrayType *arr_attnums;
+ int i;
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+ ScanKeyData scanKey[2];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ bool result;
+ Selectivity sel = 1e-5; /* fixed selectivity for now */
+
+ for (i = 0; i < natts; i++)
+ datums[i] = Int16GetDatum(attnums[i]);
+
+ get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign);
+ arr_attnums = construct_array(datums, natts,
+ INT2OID, typlen, typbyval, typalign);
+
+ rel = heap_open(Statistic2RelationId, AccessShareLock);
+
+ ScanKeyInit(&scanKey[0],
+ Anum_pg_statistic2_sta2relid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relId));
+ ScanKeyInit(&scanKey[1],
+ Anum_pg_statistic2_sta2attnums,
+ BTEqualStrategyNumber, F_ARRAY_EQ,
+ PointerGetDatum(arr_attnums));
+
+ scan = systable_beginscan(rel, Statistic2RelidAttnumsInhIndexId, true,
+ SnapshotNow, 2, scanKey);
+
+ tuple = systable_getnext(scan);
+
+ result = HeapTupleIsValid(tuple);
+
+ systable_endscan(scan);
+
+ heap_close(rel, NoLock);
+
+ pfree(datums);
+
+ if (result)
+ *result_sel = sel;
+
+ return result;
+ }
+
+ typedef struct {
+ CrossColumnClause *xc;
+ RangeQueryClause *rq;
+ } reclist;
+
+ typedef struct {
+ int len;
+ reclist *rclist;
+ AttrNumber *attnums;
+ } reclist2;
+
+
+ /* add rclist to our list, so the ordered attnums arrays are unique */
+ static void
+ add_reclist(int len, reclist *rclist, List **results)
+ {
+ ListCell *lc;
+ int i, j;
+ reclist2 *rclist2;
+ AttrNumber *attnums = (AttrNumber *) palloc(len * sizeof(AttrNumber));
+
+ /* collect the ordered varattnos from the Vars */
+ for (i = 0; i < len; i++)
+ {
+ if (rclist[i].xc)
+ attnums[i] = rclist[i].xc->varattno;
+ else
+ attnums[i] = rclist[i].rq->varattno;
+ }
+ for (i = 0; i < len - 1; i++)
+ for (j = i + 1; j < len; j++)
+ {
+ AttrNumber tmp = attnums[i];
+ attnums[i] = attnums[j];
+ attnums[j] = tmp;
+ }
+
+ /* match this ordered attnum list against the current list of attnum arrays */
+ foreach(lc, *results)
+ {
+ reclist2 *rc2 = (reclist2 *) lfirst(lc);
+
+ if (len != rc2->len)
+ continue;
+
+ for (i = 0; i < len; i++)
+ if (attnums[i] != rc2->attnums[i])
+ break;
+ if (i < len)
+ continue;
+
+ /* found */
+ return;
+ }
+
+ /* not found, add it to the list */
+ rclist2 = (reclist2 *) palloc(sizeof(reclist2));
+ rclist2->len = len;
+ rclist2->rclist = (reclist *) palloc(len * sizeof(reclist));
+ for (i = 0; i < len; i++)
+ {
+ rclist2->rclist[i].xc = rclist[i].xc;
+ rclist2->rclist[i].rq = rclist[i].rq;
+ }
+ rclist2->attnums = attnums;
+
+ *results = lappend(*results, rclist2);
+ }
+
+ static int
+ compare_reclist2(reclist2 *a, reclist2 *b)
+ {
+ int i;
+
+ if (a->len < b->len)
+ return -1;
+ else if (a->len > b->len)
+ return 1;
+
+ for (i = 0; i < a->len; i++)
+ {
+ if (a->attnums[i] < b->attnums[i])
+ return -1;
+ else if (a->attnums[i] > b->attnums[i])
+ return 1;
+ }
+
+ return 0;
+ }
+
+ static bool
+ add_reclist2(int *len, reclist2 **p_reclist2, reclist2 *rclist2)
+ {
+ int curr_len = *len;
+ int i, j;
+
+ if (curr_len == 0)
+ {
+ p_reclist2[i] = rclist2;
+ curr_len++;
+ *len = curr_len;
+ return true;
+ }
+
+ for (i = 0; i < curr_len; i++)
+ {
+ if (compare_reclist2(rclist2, p_reclist2[i]) > 0)
+ {
+ for (j = curr_len; j > i; j--)
+ p_reclist2[j] = p_reclist2[j - 1];
+ p_reclist2[i] = rclist2;
+ curr_len++;
+ *len = curr_len;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static void
+ collect_xcol_lists(int curr_depth, CrossColumnClause *xclist, RangeQueryClause *rqlist, reclist *rclist, List **results)
+ {
+ CrossColumnClause *xc_tmp;
+ RangeQueryClause *rq_tmp;
+
+ for (xc_tmp = xclist; xc_tmp; xc_tmp = xc_tmp->next)
+ {
+ if (xc_tmp->varattno == 0)
+ continue;
+
+ rclist[curr_depth].xc = xc_tmp;
+ collect_xcol_lists(curr_depth + 1, xc_tmp->next, rqlist, rclist, results);
+ add_reclist(curr_depth + 1, rclist, results);
+ rclist[curr_depth].xc = NULL;
+ }
+
+ for (rq_tmp = rqlist; rq_tmp; rq_tmp = rq_tmp->next)
+ {
+ if (rq_tmp->varattno == 0)
+ continue;
+
+ rclist[curr_depth].rq = rq_tmp;
+ collect_xcol_lists(curr_depth + 1, (xclist ? xclist->next : xclist), rq_tmp->next, rclist, results);
+ add_reclist(curr_depth + 1, rclist, results);
+ rclist[curr_depth].rq = NULL;
+ }
+ }
+
+ static bool
+ crosscolumn_selectivity(Oid relId, CrossColumnClause **xclist, RangeQueryClause **rqlist, Selectivity *result_sel)
+ {
+ CrossColumnClause *xc;
+ RangeQueryClause *rq;
+ List *resultlist = NIL;
+ ListCell *lc;
+ reclist *rclist;
+ reclist2 **p_rclist2;
+ int max_len, i;
+ Selectivity sel = 1.0;
+ bool found_xc_sel = false;
+
+ max_len = 0;
+ for (rq = *rqlist; rq; max_len++, rq = rq->next)
+ ;
+ for (xc = *xclist; xc; max_len++, xc = xc->next)
+ ;
+
+ // elog(NOTICE, "crosscolumn_selectivity max length of array %d", max_len);
+
+ rclist = (reclist *) palloc(max_len * sizeof(reclist));
+ for (i = 0; i < max_len; i++)
+ {
+ rclist[i].xc = NULL;
+ rclist[i].rq = NULL;
+ }
+
+ collect_xcol_lists(0, *xclist, *rqlist, rclist, &resultlist);
+
+ pfree(rclist);
+
+ max_len = list_length(resultlist);
+ // elog(NOTICE, "crosscolumn_selectivity list length of arrays %d", max_len);
+ p_rclist2 = (reclist2 **) palloc(max_len * sizeof(reclist2 *));
+
+ max_len = 0;
+ foreach (lc, resultlist)
+ {
+ reclist2 *rclist2 = (reclist2 *) lfirst(lc);
+
+ if (!add_reclist2(&max_len, p_rclist2, rclist2))
+ {
+ pfree(rclist2->rclist);
+ pfree(rclist2->attnums);
+ pfree(rclist2);
+ }
+ }
+ // elog(NOTICE, "crosscolumn_selectivity length of ordered/unique array of previous list %d", max_len);
+
+ list_free(resultlist);
+
+ for (i = 0; i < max_len; i++)
+ {
+ if (p_rclist2[i] == NULL)
+ continue;
+
+ if (has_xcol_selectivity(relId, p_rclist2[i]->len, p_rclist2[i]->attnums, &sel))
+ {
+ int j;
+
+ /* remove the xclist and rqlist members found in p_rclist2[i] */
+ for (j = 0; j < p_rclist2[i]->len; j++)
+ {
+ /* TODO ... */
+ }
+
+ /* also, remove later elements in p_rclist2 that has any of the removed elements */
+ /* TODO ... */
+
+ // elog(NOTICE, "crosscolumn_selectivity found xc selectivity %lf", sel);
+ found_xc_sel = true;
+ *result_sel *= sel;
+ }
+
+ pfree(p_rclist2[i]->rclist);
+ pfree(p_rclist2[i]->attnums);
+ pfree(p_rclist2[i]);
+ }
+ pfree(p_rclist2);
+
+ return found_xc_sel;
+ }
diff -dcrpN postgresql.orig/src/backend/parser/gram.y postgresql/src/backend/parser/gram.y
*** postgresql.orig/src/backend/parser/gram.y 2011-04-26 09:54:04.055359065 +0200
--- postgresql/src/backend/parser/gram.y 2011-04-28 14:21:14.739176296 +0200
*************** static void SplitColQualList(List *qualL
*** 199,209 ****
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
CreateAssertStmt CreateTrigStmt
! CreateUserStmt CreateUserMappingStmt CreateRoleStmt
! CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
! DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
! DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
--- 199,210 ----
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
CreateAssertStmt CreateTrigStmt
! CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatedbStmt
! CreateCCStmt CreateESStmt
! DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
! DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropCCStmt DropESStmt
! DropRoleStmt DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
*************** static void SplitColQualList(List *qualL
*** 315,320 ****
--- 316,323 ----
%type <list> opt_fdw_options fdw_options
%type <defelt> fdw_option
+ %type <list> cc_column_list
+
%type <range> OptTempTableName
%type <into> into_clause create_as_target
*************** static void SplitColQualList(List *qualL
*** 499,505 ****
DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
! EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN
EXTENSION EXTERNAL EXTRACT
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
--- 502,508 ----
DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
! EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION
EXTENSION EXTERNAL EXTRACT
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
*************** stmt :
*** 700,707 ****
--- 703,712 ----
| CreateAsStmt
| CreateAssertStmt
| CreateCastStmt
+ | CreateCCStmt
| CreateConversionStmt
| CreateDomainStmt
+ | CreateESStmt
| CreateExtensionStmt
| CreateFdwStmt
| CreateForeignServerStmt
*************** stmt :
*** 729,734 ****
--- 734,741 ----
| DoStmt
| DropAssertStmt
| DropCastStmt
+ | DropCCStmt
+ | DropESStmt
| DropFdwStmt
| DropForeignServerStmt
| DropGroupStmt
*************** schema_stmt:
*** 1190,1195 ****
--- 1197,1267 ----
/*****************************************************************************
*
+ * Create cross column / expression statistics
+ *
+ *****************************************************************************/
+
+ CreateCCStmt:
+ CREATE CROSS COLUMN STATISTICS ON qualified_name '(' cc_column_list ')'
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+ n->create = TRUE;
+ n->relation = $6;
+ n->columns = $8;
+ n->expr = NULL;
+ $$ = (Node *)n;
+ }
+ ;
+
+ DropCCStmt:
+ DROP CROSS COLUMN STATISTICS ON qualified_name '(' cc_column_list ')'
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+ n->create = FALSE;
+ n->relation = $6;
+ n->columns = $8;
+ n->expr = NULL;
+ $$ = (Node *)n;
+ }
+ ;
+
+ cc_column_list:
+ columnref
+ {
+ $$ = list_make1($1);
+ }
+ | cc_column_list ',' columnref
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+ CreateESStmt:
+ CREATE EXPRESSION STATISTICS ON qualified_name '(' a_expr ')'
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+ n->create = TRUE;
+ n->relation = $5;
+ n->columns = NIL;
+ n->expr = $7;
+ $$ = (Node *)n;
+ }
+ ;
+
+ DropESStmt:
+ DROP EXPRESSION STATISTICS ON qualified_name '(' a_expr ')'
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+ n->create = FALSE;
+ n->relation = $5;
+ n->columns = NIL;
+ n->expr = $7;
+ $$ = (Node *)n;
+ }
+ ;
+
+ /*****************************************************************************
+ *
* Set PG internal variable
* SET name TO 'var_value'
* Include SQL92 syntax (thomas 1997-10-22):
*************** unreserved_keyword:
*** 11898,11903 ****
--- 11970,11976 ----
| EXCLUSIVE
| EXECUTE
| EXPLAIN
+ | EXPRESSION
| EXTENSION
| EXTERNAL
| FAMILY
diff -dcrpN postgresql.orig/src/backend/parser/parse_utilcmd.c postgresql/src/backend/parser/parse_utilcmd.c
*** postgresql.orig/src/backend/parser/parse_utilcmd.c 2011-04-26 09:54:04.062358585 +0200
--- postgresql/src/backend/parser/parse_utilcmd.c 2011-04-28 14:21:14.745175892 +0200
*************** setSchemaName(char *context_schema, char
*** 2700,2702 ****
--- 2700,2878 ----
"different from the one being created (%s)",
*stmt_schema_name, context_schema)));
}
+
+ /*
+ *
+ */
+ bool
+ set_location_unknown_walker(Node *node, void *dummy)
+ {
+ if (node == NULL)
+ return false;
+
+ switch (node->type)
+ {
+ case T_TypeName:
+ {
+ TypeName *n = (TypeName *) node;
+ n->location = -1;
+ }
+ break;
+ case T_ColumnRef:
+ {
+ ColumnRef *n = (ColumnRef *)node;
+ n->location = -1;
+ }
+ break;
+ case T_ParamRef:
+ {
+ ParamRef *n = (ParamRef *) node;
+ n->location = -1;
+ }
+ break;
+ case T_A_Expr:
+ {
+ A_Expr *n = (A_Expr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_A_Const:
+ {
+ A_Const *n = (A_Const *) node;
+ n->location = -1;
+ }
+ break;
+ case T_TypeCast:
+ {
+ TypeCast *n = (TypeCast *) node;
+ n->location = -1;
+ }
+ break;
+ case T_FuncCall:
+ {
+ FuncCall *n = (FuncCall *) node;
+ n->location = -1;
+ }
+ break;
+ case T_A_ArrayExpr:
+ {
+ A_ArrayExpr *n = (A_ArrayExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_Var:
+ {
+ Var *n = (Var *) node;
+ n->location = -1;
+ }
+ break;
+ case T_Const:
+ {
+ Const *n = (Const *) node;
+ n->location = -1;
+ }
+ break;
+ case T_FuncExpr:
+ {
+ FuncExpr *n = (FuncExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_OpExpr:
+ {
+ OpExpr *n = (OpExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_DistinctExpr:
+ {
+ DistinctExpr *n = (DistinctExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_ScalarArrayOpExpr:
+ {
+ ScalarArrayOpExpr *n = (ScalarArrayOpExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_BoolExpr:
+ {
+ BoolExpr *n = (BoolExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_CaseExpr:
+ {
+ CaseExpr *n = (CaseExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_CaseWhen:
+ {
+ CaseWhen *n = (CaseWhen *) node;
+ n->location = -1;
+ }
+ break;
+ case T_ArrayExpr:
+ {
+ ArrayExpr *n = (ArrayExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_CoalesceExpr:
+ {
+ CoalesceExpr *n = (CoalesceExpr *) node;
+ n->location = -1;
+ }
+ break;
+ case T_CoerceToDomain:
+ {
+ CoerceToDomain *n = (CoerceToDomain *) node;
+ n->location = -1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return expression_tree_walker(node, set_location_unknown_walker, NULL);
+ }
+
+ /*
+ * transformExtraStatistics
+ * Transform the column list or the expression into a form
+ * usable by the executor.
+ */
+ ExtraStatStmt *
+ transformExtraStatistics(ExtraStatStmt *stmt, const char *queryString)
+ {
+ ParseState *pstate;
+ RangeTblEntry *rte;
+ ExtraStatStmt *newstmt;
+ List *columns = NIL;
+ ListCell *cell;
+
+ pstate = make_parsestate(NULL);
+ pstate->p_sourcetext = queryString;
+
+ rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true);
+ addRTEtoQuery(pstate, rte, true, true, true);
+
+ newstmt = makeNode(ExtraStatStmt);
+ newstmt->create = stmt->create;
+ newstmt->relation = copyObject(stmt->relation);
+
+ foreach(cell, stmt->columns)
+ {
+ Node *col = lfirst(cell);
+
+ columns = lappend(columns, transformExpr(pstate, col));
+ }
+
+ newstmt->columns = columns;
+ newstmt->expr = transformExpr(pstate, stmt->expr);
+ query_or_expression_tree_walker(newstmt->expr, set_location_unknown_walker, NULL, 0);
+
+ return newstmt;
+ }
diff -dcrpN postgresql.orig/src/backend/tcop/utility.c postgresql/src/backend/tcop/utility.c
*** postgresql.orig/src/backend/tcop/utility.c 2011-04-26 09:54:04.075357697 +0200
--- postgresql/src/backend/tcop/utility.c 2011-04-28 14:21:14.748175689 +0200
*************** check_xact_readonly(Node *parsetree)
*** 229,234 ****
--- 229,235 ----
case T_AlterTableSpaceOptionsStmt:
case T_CreateForeignTableStmt:
case T_SecLabelStmt:
+ case T_ExtraStatStmt:
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
break;
default:
*************** standard_ProcessUtility(Node *parsetree,
*** 573,578 ****
--- 574,587 ----
}
break;
+ case T_ExtraStatStmt:
+ {
+ ExtraStatStmt *newstmt = transformExtraStatistics((ExtraStatStmt *)parsetree, queryString);
+
+ ExtraStatistics(newstmt);
+ }
+ break;
+
case T_CreateTableSpaceStmt:
PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
*************** CreateCommandTag(Node *parsetree)
*** 1734,1739 ****
--- 1743,1771 ----
tag = "CREATE FOREIGN TABLE";
break;
+ case T_ExtraStatStmt:
+ {
+ ExtraStatStmt *stmt = (ExtraStatStmt *)parsetree;
+
+ if (list_length(stmt->columns) > 0)
+ {
+ if (stmt->create)
+ tag = "CREATE CROSS COLUMN STATISTICS";
+ else
+ tag = "DROP CROSS COLUMN STATISTICS";
+ }
+ else if (stmt->expr != NULL)
+ {
+ if (stmt->create)
+ tag = "CREATE EXPRESSION STATISTICS";
+ else
+ tag = "DROP EXPRESSION STATISTICS";
+ }
+ else
+ tag = "???";
+ }
+ break;
+
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
diff -dcrpN postgresql.orig/src/backend/tsearch/ts_selfuncs.c postgresql/src/backend/tsearch/ts_selfuncs.c
*** postgresql.orig/src/backend/tsearch/ts_selfuncs.c 2011-04-11 15:36:27.150812982 +0200
--- postgresql/src/backend/tsearch/ts_selfuncs.c 2011-04-28 14:21:14.749175621 +0200
*************** tsquerysel(VariableStatData *vardata, Da
*** 169,175 ****
stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
/* MCELEM will be an array of TEXT elements for a tsvector column */
! if (get_attstatsslot(vardata->statsTuple,
TEXTOID, -1,
STATISTIC_KIND_MCELEM, InvalidOid,
NULL,
--- 169,175 ----
stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
/* MCELEM will be an array of TEXT elements for a tsvector column */
! if (get_attstatsslot(vardata->statsTuple, STAT_VARIABLE,
TEXTOID, -1,
STATISTIC_KIND_MCELEM, InvalidOid,
NULL,
diff -dcrpN postgresql.orig/src/backend/utils/adt/selfuncs.c postgresql/src/backend/utils/adt/selfuncs.c
*** postgresql.orig/src/backend/utils/adt/selfuncs.c 2011-04-26 09:54:04.094356395 +0200
--- postgresql/src/backend/utils/adt/selfuncs.c 2011-04-28 15:53:46.195302017 +0200
***************
*** 94,102 ****
--- 94,104 ----
#include "access/gin.h"
#include "access/sysattr.h"
#include "catalog/index.h"
+ #include "catalog/indexing.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_statistic.h"
+ #include "catalog/pg_statistic3.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "mb/pg_wchar.h"
***************
*** 111,116 ****
--- 113,119 ----
#include "optimizer/restrictinfo.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
+ #include "parser/parse_utilcmd.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/bytea.h"
*************** var_eq_const(VariableStatData *vardata,
*** 275,281 ****
* don't like this, maybe you shouldn't be using eqsel for your
* operator...)
*/
! if (get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
--- 278,284 ----
* don't like this, maybe you shouldn't be using eqsel for your
* operator...)
*/
! if (get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
*************** var_eq_non_const(VariableStatData *varda
*** 417,423 ****
* Cross-check: selectivity should never be estimated as more than the
* most common value's.
*/
! if (get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
--- 420,426 ----
* Cross-check: selectivity should never be estimated as more than the
* most common value's.
*/
! if (get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
*************** mcv_selectivity(VariableStatData *vardat
*** 588,594 ****
sumcommon = 0.0;
if (HeapTupleIsValid(vardata->statsTuple) &&
! get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
--- 591,597 ----
sumcommon = 0.0;
if (HeapTupleIsValid(vardata->statsTuple) &&
! get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
*************** histogram_selectivity(VariableStatData *
*** 664,670 ****
Assert(min_hist_size > 2 * n_skip);
if (HeapTupleIsValid(vardata->statsTuple) &&
! get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, InvalidOid,
NULL,
--- 667,673 ----
Assert(min_hist_size > 2 * n_skip);
if (HeapTupleIsValid(vardata->statsTuple) &&
! get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, InvalidOid,
NULL,
*************** ineq_histogram_selectivity(PlannerInfo *
*** 741,747 ****
* the reverse way if isgt is TRUE.
*/
if (HeapTupleIsValid(vardata->statsTuple) &&
! get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, InvalidOid,
&hist_op,
--- 744,750 ----
* the reverse way if isgt is TRUE.
*/
if (HeapTupleIsValid(vardata->statsTuple) &&
! get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, InvalidOid,
&hist_op,
*************** booltestsel(PlannerInfo *root, BoolTestT
*** 1434,1440 ****
stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
freq_null = stats->stanullfrac;
! if (get_attstatsslot(vardata.statsTuple,
vardata.atttype, vardata.atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
--- 1437,1443 ----
stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
freq_null = stats->stanullfrac;
! if (get_attstatsslot(vardata.statsTuple, vardata.stats_type,
vardata.atttype, vardata.atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
*************** eqjoinsel_inner(Oid operator,
*** 2074,2080 ****
if (HeapTupleIsValid(vardata1->statsTuple))
{
stats1 = (Form_pg_statistic) GETSTRUCT(vardata1->statsTuple);
! have_mcvs1 = get_attstatsslot(vardata1->statsTuple,
vardata1->atttype,
vardata1->atttypmod,
STATISTIC_KIND_MCV,
--- 2077,2083 ----
if (HeapTupleIsValid(vardata1->statsTuple))
{
stats1 = (Form_pg_statistic) GETSTRUCT(vardata1->statsTuple);
! have_mcvs1 = get_attstatsslot(vardata1->statsTuple, vardata1->stats_type,
vardata1->atttype,
vardata1->atttypmod,
STATISTIC_KIND_MCV,
*************** eqjoinsel_inner(Oid operator,
*** 2087,2093 ****
if (HeapTupleIsValid(vardata2->statsTuple))
{
stats2 = (Form_pg_statistic) GETSTRUCT(vardata2->statsTuple);
! have_mcvs2 = get_attstatsslot(vardata2->statsTuple,
vardata2->atttype,
vardata2->atttypmod,
STATISTIC_KIND_MCV,
--- 2090,2096 ----
if (HeapTupleIsValid(vardata2->statsTuple))
{
stats2 = (Form_pg_statistic) GETSTRUCT(vardata2->statsTuple);
! have_mcvs2 = get_attstatsslot(vardata2->statsTuple, vardata2->stats_type,
vardata2->atttype,
vardata2->atttypmod,
STATISTIC_KIND_MCV,
*************** eqjoinsel_semi(Oid operator,
*** 2309,2315 ****
if (HeapTupleIsValid(vardata1->statsTuple))
{
stats1 = (Form_pg_statistic) GETSTRUCT(vardata1->statsTuple);
! have_mcvs1 = get_attstatsslot(vardata1->statsTuple,
vardata1->atttype,
vardata1->atttypmod,
STATISTIC_KIND_MCV,
--- 2312,2318 ----
if (HeapTupleIsValid(vardata1->statsTuple))
{
stats1 = (Form_pg_statistic) GETSTRUCT(vardata1->statsTuple);
! have_mcvs1 = get_attstatsslot(vardata1->statsTuple, vardata1->stats_type,
vardata1->atttype,
vardata1->atttypmod,
STATISTIC_KIND_MCV,
*************** eqjoinsel_semi(Oid operator,
*** 2321,2327 ****
if (HeapTupleIsValid(vardata2->statsTuple))
{
! have_mcvs2 = get_attstatsslot(vardata2->statsTuple,
vardata2->atttype,
vardata2->atttypmod,
STATISTIC_KIND_MCV,
--- 2324,2330 ----
if (HeapTupleIsValid(vardata2->statsTuple))
{
! have_mcvs2 = get_attstatsslot(vardata2->statsTuple, vardata2->stats_type,
vardata2->atttype,
vardata2->atttypmod,
STATISTIC_KIND_MCV,
*************** estimate_hash_bucketsize(PlannerInfo *ro
*** 3322,3328 ****
if (HeapTupleIsValid(vardata.statsTuple))
{
! if (get_attstatsslot(vardata.statsTuple,
vardata.atttype, vardata.atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
--- 3325,3331 ----
if (HeapTupleIsValid(vardata.statsTuple))
{
! if (get_attstatsslot(vardata.statsTuple, vardata.stats_type,
vardata.atttype, vardata.atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
*************** examine_variable(PlannerInfo *root, Node
*** 4103,4108 ****
--- 4106,4112 ----
{
Node *basenode;
Relids varnos;
+ int onerelid = 0;
RelOptInfo *onerel;
/* Make sure we don't return dangling pointers in vardata */
*************** examine_variable(PlannerInfo *root, Node
*** 4147,4152 ****
--- 4151,4157 ----
}
else if (rte->rtekind == RTE_RELATION)
{
+ vardata->stats_type = STAT_VARIABLE;
vardata->statsTuple = SearchSysCache3(STATRELATTINH,
ObjectIdGetDatum(rte->relid),
Int16GetDatum(var->varattno),
*************** examine_variable(PlannerInfo *root, Node
*** 4185,4192 ****
case BMS_SINGLETON:
if (varRelid == 0 || bms_is_member(varRelid, varnos))
{
! onerel = find_base_rel(root,
! (varRelid ? varRelid : bms_singleton_member(varnos)));
vardata->rel = onerel;
node = basenode; /* strip any relabeling */
}
--- 4190,4197 ----
case BMS_SINGLETON:
if (varRelid == 0 || bms_is_member(varRelid, varnos))
{
! onerelid = (varRelid ? varRelid : bms_singleton_member(varnos));
! onerel = find_base_rel(root, onerelid);
vardata->rel = onerel;
node = basenode; /* strip any relabeling */
}
*************** examine_variable(PlannerInfo *root, Node
*** 4220,4233 ****
{
/*
* We have an expression in vars of a single relation. Try to match
! * it to expressional index columns, in hopes of finding some
! * statistics.
*
* XXX it's conceivable that there are multiple matches with different
* index opfamilies; if so, we need to pick one that matches the
* operator we are estimating for. FIXME later.
*/
ListCell *ilist;
foreach(ilist, onerel->indexlist)
{
--- 4225,4301 ----
{
/*
* We have an expression in vars of a single relation. Try to match
! * it to expression statistics first then to expressional index columns,
! * in hopes of finding some statistics.
*
* XXX it's conceivable that there are multiple matches with different
* index opfamilies; if so, we need to pick one that matches the
* operator we are estimating for. FIXME later.
*/
ListCell *ilist;
+ Node *expr = copyObject(node);
+ char *exprbin;
+ Datum exprbindatum;
+
+ #define USE_SYSCACHE_FOR_SEARCH 0
+ #if !USE_SYSCACHE_FOR_SEARCH
+ Relation rel;
+ ScanKeyData scanKey[2];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ #endif
+
+ query_or_expression_tree_walker(expr, set_location_unknown_walker, NULL, 0);
+ exprbin = nodeToString(expr);
+ exprbindatum = CStringGetTextDatum(exprbin);
+
+ #if USE_SYSCACHE_FOR_SEARCH
+ vardata->statsTuple = SearchSysCache3(STAT3RELEXPRINH,
+ ObjectIdGetDatum(root->simple_rte_array[onerelid]->relid),
+ exprbindatum,
+ BoolGetDatum(false));
+ if (HeapTupleIsValid(vardata->statsTuple))
+ {
+ vardata->stats_type = STAT_EXPRESSION;
+ vardata->freefunc = ReleaseSysCache;
+ return;
+ }
+
+ #else
+
+ rel = heap_open(Statistic3RelationId, RowShareLock);
+
+ ScanKeyInit(&scanKey[0],
+ Anum_pg_statistic3_sta3relid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(root->simple_rte_array[onerelid]->relid));
+ ScanKeyInit(&scanKey[1],
+ Anum_pg_statistic3_sta3expr,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ exprbindatum);
+
+ scan = systable_beginscan(rel, Statistic3RelidExprInhIndexId, true,
+ SnapshotNow, 2, scanKey);
+
+ tuple = systable_getnext(scan);
+ if (HeapTupleIsValid(tuple))
+ {
+ // elog(NOTICE, "examine_variable expression found");
+ vardata->stats_type = STAT_EXPRESSION;
+ vardata->statsTuple = heap_copytuple(tuple);
+ vardata->freefunc = heap_freetuple;
+ }
+
+ systable_endscan(scan);
+
+ pfree(exprbin);
+ pfree(DatumGetPointer(exprbindatum));
+
+ relation_close(rel, RowShareLock);
+
+ if (vardata->statsTuple)
+ return;
+ #endif
foreach(ilist, onerel->indexlist)
{
*************** examine_variable(PlannerInfo *root, Node
*** 4286,4291 ****
--- 4354,4360 ----
}
else if (index->indpred == NIL)
{
+ vardata->stats_type = STAT_VARIABLE;
vardata->statsTuple =
SearchSysCache3(STATRELATTINH,
ObjectIdGetDatum(index->indexoid),
*************** get_variable_numdistinct(VariableStatDat
*** 4327,4337 ****
*/
if (HeapTupleIsValid(vardata->statsTuple))
{
! /* Use the pg_statistic entry */
! Form_pg_statistic stats;
! stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
! stadistinct = stats->stadistinct;
}
else if (vardata->vartype == BOOLOID)
{
--- 4396,4425 ----
*/
if (HeapTupleIsValid(vardata->statsTuple))
{
! switch (vardata->stats_type)
! {
! case STAT_VARIABLE:
! {
! /* Use the pg_statistic entry */
! Form_pg_statistic stats;
! stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
! stadistinct = stats->stadistinct;
! break;
! }
! case STAT_EXPRESSION:
! {
! /* Use the pg_statistic entry */
! Form_pg_statistic3 stats3;
!
! stats3 = (Form_pg_statistic3) GETSTRUCT(vardata->statsTuple);
! stadistinct = stats3->sta3distinct;
! break;
! }
! default:
! elog(ERROR, "internal error");
! return 0.0;
! }
}
else if (vardata->vartype == BOOLOID)
{
*************** get_variable_range(PlannerInfo *root, Va
*** 4462,4468 ****
* the one we want, fail --- this suggests that there is data we can't
* use.
*/
! if (get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, sortop,
NULL,
--- 4550,4556 ----
* the one we want, fail --- this suggests that there is data we can't
* use.
*/
! if (get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, sortop,
NULL,
*************** get_variable_range(PlannerInfo *root, Va
*** 4477,4483 ****
}
free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
}
! else if (get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, InvalidOid,
NULL,
--- 4565,4571 ----
}
free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
}
! else if (get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_HISTOGRAM, InvalidOid,
NULL,
*************** get_variable_range(PlannerInfo *root, Va
*** 4494,4500 ****
* the MCVs. However, usually the MCVs will not be the extreme values, so
* avoid unnecessary data copying.
*/
! if (get_attstatsslot(vardata->statsTuple,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
--- 4582,4588 ----
* the MCVs. However, usually the MCVs will not be the extreme values, so
* avoid unnecessary data copying.
*/
! if (get_attstatsslot(vardata->statsTuple, vardata->stats_type,
vardata->atttype, vardata->atttypmod,
STATISTIC_KIND_MCV, InvalidOid,
NULL,
*************** btcostestimate(PG_FUNCTION_ARGS)
*** 6255,6260 ****
--- 6343,6349 ----
}
else
{
+ vardata.stats_type = STAT_VARIABLE;
vardata.statsTuple = SearchSysCache3(STATRELATTINH,
ObjectIdGetDatum(relid),
Int16GetDatum(colnum),
*************** btcostestimate(PG_FUNCTION_ARGS)
*** 6281,6286 ****
--- 6370,6376 ----
}
else
{
+ vardata.stats_type = STAT_VARIABLE;
vardata.statsTuple = SearchSysCache3(STATRELATTINH,
ObjectIdGetDatum(relid),
Int16GetDatum(colnum),
*************** btcostestimate(PG_FUNCTION_ARGS)
*** 6300,6306 ****
index->opcintype[0],
BTLessStrategyNumber);
if (OidIsValid(sortop) &&
! get_attstatsslot(vardata.statsTuple, InvalidOid, 0,
STATISTIC_KIND_CORRELATION,
sortop,
NULL,
--- 6390,6396 ----
index->opcintype[0],
BTLessStrategyNumber);
if (OidIsValid(sortop) &&
! get_attstatsslot(vardata.statsTuple, vardata.stats_type, InvalidOid, 0,
STATISTIC_KIND_CORRELATION,
sortop,
NULL,
diff -dcrpN postgresql.orig/src/backend/utils/cache/catcache.c postgresql/src/backend/utils/cache/catcache.c
*** postgresql.orig/src/backend/utils/cache/catcache.c 2011-04-13 10:11:05.021216766 +0200
--- postgresql/src/backend/utils/cache/catcache.c 2011-04-28 14:21:14.766174476 +0200
*************** GetCCHashEqFuncs(Oid keytype, PGFunction
*** 135,140 ****
--- 135,141 ----
*eqfunc = F_INT4EQ;
break;
case TEXTOID:
+ case PGNODETREEOID:
*hashfunc = hashtext;
*eqfunc = F_TEXTEQ;
diff -dcrpN postgresql.orig/src/backend/utils/cache/lsyscache.c postgresql/src/backend/utils/cache/lsyscache.c
*** postgresql.orig/src/backend/utils/cache/lsyscache.c 2011-04-11 15:36:27.175811226 +0200
--- postgresql/src/backend/utils/cache/lsyscache.c 2011-04-28 14:21:14.769174273 +0200
***************
*** 27,32 ****
--- 27,33 ----
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h"
+ #include "catalog/pg_statistic3.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
*************** get_attavgwidth(Oid relid, AttrNumber at
*** 2667,2680 ****
* type ID to pass to free_attstatsslot later.
*/
bool
! get_attstatsslot(HeapTuple statstuple,
Oid atttype, int32 atttypmod,
int reqkind, Oid reqop,
Oid *actualop,
Datum **values, int *nvalues,
float4 **numbers, int *nnumbers)
{
! Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
int i,
j;
Datum val;
--- 2668,2682 ----
* type ID to pass to free_attstatsslot later.
*/
bool
! get_attstatsslot(HeapTuple statstuple, StatType stat_type,
Oid atttype, int32 atttypmod,
int reqkind, Oid reqop,
Oid *actualop,
Datum **values, int *nvalues,
float4 **numbers, int *nnumbers)
{
! Form_pg_statistic stats;
! Form_pg_statistic3 stats3;
int i,
j;
Datum val;
*************** get_attstatsslot(HeapTuple statstuple,
*** 2685,2707 ****
HeapTuple typeTuple;
Form_pg_type typeForm;
! for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
{
! if ((&stats->stakind1)[i] == reqkind &&
! (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
break;
}
if (i >= STATISTIC_NUM_SLOTS)
return false; /* not there */
if (actualop)
! *actualop = (&stats->staop1)[i];
if (values)
{
! val = SysCacheGetAttr(STATRELATTINH, statstuple,
Anum_pg_statistic_stavalues1 + i,
&isnull);
if (isnull)
elog(ERROR, "stavalues is null");
statarray = DatumGetArrayTypeP(val);
--- 2687,2755 ----
HeapTuple typeTuple;
Form_pg_type typeForm;
! switch (stat_type)
{
! case STAT_VARIABLE:
! stats = (Form_pg_statistic) GETSTRUCT(statstuple);
! stats3 = NULL;
!
! for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
! {
! if ((&stats->stakind1)[i] == reqkind &&
! (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
! break;
! }
break;
+ case STAT_EXPRESSION:
+ stats = NULL;
+ stats3 = (Form_pg_statistic3) GETSTRUCT(statstuple);
+
+ for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
+ {
+ if ((&stats3->sta3kind1)[i] == reqkind &&
+ (reqop == InvalidOid || (&stats3->sta3op1)[i] == reqop))
+ break;
+ }
+ break;
+ default:
+ elog(ERROR, "internal error");
+ return false; /* make compiler quiet */
}
+
if (i >= STATISTIC_NUM_SLOTS)
return false; /* not there */
if (actualop)
! {
! switch (stat_type)
! {
! case STAT_VARIABLE:
! *actualop = (&stats->staop1)[i];
! break;
! case STAT_EXPRESSION:
! *actualop = (&stats3->sta3op1)[i];
! break;
! }
! }
if (values)
{
! switch (stat_type)
! {
! case STAT_VARIABLE:
! val = SysCacheGetAttr(STATRELATTINH, statstuple,
Anum_pg_statistic_stavalues1 + i,
&isnull);
+ break;
+ case STAT_EXPRESSION:
+ val = SysCacheGetAttr(STAT3RELEXPRINH, statstuple,
+ Anum_pg_statistic3_sta3values1 + i,
+ &isnull);
+ break;
+ default:
+ elog(ERROR, "internal error");
+ return false; /* silence compiler */
+ }
if (isnull)
elog(ERROR, "stavalues is null");
statarray = DatumGetArrayTypeP(val);
*************** get_attstatsslot(HeapTuple statstuple,
*** 2753,2761 ****
if (numbers)
{
! val = SysCacheGetAttr(STATRELATTINH, statstuple,
Anum_pg_statistic_stanumbers1 + i,
&isnull);
if (isnull)
elog(ERROR, "stanumbers is null");
statarray = DatumGetArrayTypeP(val);
--- 2801,2821 ----
if (numbers)
{
! switch (stat_type)
! {
! case STAT_VARIABLE:
! val = SysCacheGetAttr(STATRELATTINH, statstuple,
Anum_pg_statistic_stanumbers1 + i,
&isnull);
+ break;
+ case STAT_EXPRESSION:
+ val = SysCacheGetAttr(STAT3RELEXPRINH, statstuple,
+ Anum_pg_statistic3_sta3numbers1 + i,
+ &isnull);
+ break;
+ default:
+ return false; /* silence compiler */
+ }
if (isnull)
elog(ERROR, "stanumbers is null");
statarray = DatumGetArrayTypeP(val);
diff -dcrpN postgresql.orig/src/backend/utils/cache/syscache.c postgresql/src/backend/utils/cache/syscache.c
*** postgresql.orig/src/backend/utils/cache/syscache.c 2011-04-26 09:54:04.095356326 +0200
--- postgresql/src/backend/utils/cache/syscache.c 2011-04-28 14:21:14.775173869 +0200
***************
*** 45,50 ****
--- 45,51 ----
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h"
+ #include "catalog/pg_statistic3.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_config_map.h"
*************** static const struct cachedesc cacheinfo[
*** 587,592 ****
--- 588,604 ----
},
1024
},
+ {Statistic3RelationId, /* STAT3RELEXPRINH */
+ Statistic3RelidExprInhIndexId,
+ 3,
+ {
+ Anum_pg_statistic3_sta3relid,
+ Anum_pg_statistic3_sta3expr,
+ Anum_pg_statistic3_sta3inherit,
+ 0
+ },
+ 1024
+ },
{StatisticRelationId, /* STATRELATTINH */
StatisticRelidAttnumInhIndexId,
3,
diff -dcrpN postgresql.orig/src/include/catalog/indexing.h postgresql/src/include/catalog/indexing.h
*** postgresql.orig/src/include/catalog/indexing.h 2011-02-10 10:36:32.320680534 +0100
--- postgresql/src/include/catalog/indexing.h 2011-04-28 14:21:14.777173734 +0200
*************** DECLARE_UNIQUE_INDEX(pg_extension_oid_in
*** 300,305 ****
--- 300,312 ----
DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, on pg_extension using btree(extname name_ops));
#define ExtensionNameIndexId 3081
+ DECLARE_UNIQUE_INDEX(pg_statistic2_relid_att_inh_index, 3072, on pg_statistic2 using btree(sta2relid oid_ops, sta2attnums array_ops, sta2inherit bool_ops));
+ #define Statistic2RelidAttnumsInhIndexId 3072
+
+ DECLARE_UNIQUE_INDEX(pg_statistic3_relid_expr_inh_index, 3074, on pg_statistic3 using btree(sta3relid oid_ops, sta3expr text_ops, sta3inherit bool_ops));
+ #define Statistic3RelidExprInhIndexId 3074
+
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
diff -dcrpN postgresql.orig/src/include/catalog/pg_statistic2.h postgresql/src/include/catalog/pg_statistic2.h
*** postgresql.orig/src/include/catalog/pg_statistic2.h 1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/include/catalog/pg_statistic2.h 2011-04-28 14:21:14.779173600 +0200
***************
*** 0 ****
--- 1,265 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_statistic2.h
+ * definition of the system "cross-column statistic" relation (pg_statistic2)
+ * along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_statistic2.h
+ *
+ * NOTES
+ * the genbki.pl script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef PG_STATISTIC2_H
+ #define PG_STATISTIC2_H
+
+ #include "catalog/genbki.h"
+
+ /*
+ * The CATALOG definition has to refer to the type of stavaluesN as
+ * "anyarray" so that bootstrap mode recognizes it. There is no real
+ * typedef for that, however. Since the fields are potentially-null and
+ * therefore can't be accessed directly from C code, there is no particular
+ * need for the C struct definition to show a valid field type --- instead
+ * we just make it int.
+ */
+ #define anyarray int
+
+ /* ----------------
+ * pg_statistic2 definition. cpp turns this into
+ * typedef struct FormData_pg_statistic2
+ * ----------------
+ */
+ #define Statistic2RelationId 3071
+
+ CATALOG(pg_statistic2,3071) BKI_WITHOUT_OIDS
+ {
+ /* These fields form the unique key for the entry: */
+ Oid sta2relid; /* relation containing attribute */
+ int2 sta2attnums[1]; /* attribute (column) stats are for */
+ bool sta2inherit; /* true if inheritance children are included */
+
+ /* the fraction of the column's entries that are NULL: */
+ float4 sta2nullfrac;
+
+ /*
+ * stawidth is the average width in bytes of non-null entries. For
+ * fixed-width datatypes this is of course the same as the typlen, but for
+ * var-width types it is more useful. Note that this is the average width
+ * of the data as actually stored, post-TOASTing (eg, for a
+ * moved-out-of-line value, only the size of the pointer object is
+ * counted). This is the appropriate definition for the primary use of
+ * the statistic, which is to estimate sizes of in-memory hash tables of
+ * tuples.
+ */
+ int4 sta2width;
+
+ /* ----------------
+ * stadistinct indicates the (approximate) number of distinct non-null
+ * data values in the column. The interpretation is:
+ * 0 unknown or not computed
+ * > 0 actual number of distinct values
+ * < 0 negative of multiplier for number of rows
+ * The special negative case allows us to cope with columns that are
+ * unique (stadistinct = -1) or nearly so (for example, a column in
+ * which values appear about twice on the average could be represented
+ * by stadistinct = -0.5). Because the number-of-rows statistic in
+ * pg_class may be updated more frequently than pg_statistic2 is, it's
+ * important to be able to describe such situations as a multiple of
+ * the number of rows, rather than a fixed number of distinct values.
+ * But in other cases a fixed number is correct (eg, a boolean column).
+ * ----------------
+ */
+ float4 sta2distinct;
+
+ /* ----------------
+ * To allow keeping statistics on different kinds of datatypes,
+ * we do not hard-wire any particular meaning for the remaining
+ * statistical fields. Instead, we provide several "slots" in which
+ * statistical data can be placed. Each slot includes:
+ * kind integer code identifying kind of data
+ * op OID of associated operator, if needed
+ * numbers float4 array (for statistical values)
+ * values anyarray (for representations of data values)
+ * The ID and operator fields are never NULL; they are zeroes in an
+ * unused slot. The numbers and values fields are NULL in an unused
+ * slot, and might also be NULL in a used slot if the slot kind has
+ * no need for one or the other.
+ * ----------------
+ */
+
+ int2 sta2kind1;
+ int2 sta2kind2;
+ int2 sta2kind3;
+ int2 sta2kind4;
+
+ Oid sta2op1;
+ Oid sta2op2;
+ Oid sta2op3;
+ Oid sta2op4;
+
+ /*
+ * THE REST OF THESE ARE VARIABLE LENGTH FIELDS, and may even be absent
+ * (NULL). They cannot be accessed as C struct entries; you have to use
+ * the full field access machinery (heap_getattr) for them. We declare
+ * them here for the catalog machinery.
+ */
+
+ float4 sta2numbers1[1];
+ float4 sta2numbers2[1];
+ float4 sta2numbers3[1];
+ float4 sta2numbers4[1];
+
+ /*
+ * Values in these arrays are values of the column's data type. We
+ * presently have to cheat quite a bit to allow polymorphic arrays of this
+ * kind, but perhaps someday it'll be a less bogus facility.
+ */
+ anyarray sta2values1;
+ anyarray sta2values2;
+ anyarray sta2values3;
+ anyarray sta2values4;
+ } FormData_pg_statistic2;
+
+ #define STATISTIC_NUM_SLOTS 4
+
+ #undef anyarray
+
+
+ /* ----------------
+ * Form_pg_statistic2 corresponds to a pointer to a tuple with
+ * the format of pg_statistic2 relation.
+ * ----------------
+ */
+ typedef FormData_pg_statistic2 *Form_pg_statistic2;
+
+ /* ----------------
+ * compiler constants for pg_statistic2
+ * ----------------
+ */
+ #define Natts_pg_statistic2 22
+ #define Anum_pg_statistic2_sta2relid 1
+ #define Anum_pg_statistic2_sta2attnums 2
+ #define Anum_pg_statistic2_sta2inherit 3
+ #define Anum_pg_statistic2_sta2nullfrac 4
+ #define Anum_pg_statistic2_sta2width 5
+ #define Anum_pg_statistic2_sta2distinct 6
+ #define Anum_pg_statistic2_sta2kind1 7
+ #define Anum_pg_statistic2_sta2kind2 8
+ #define Anum_pg_statistic2_sta2kind3 9
+ #define Anum_pg_statistic2_sta2kind4 10
+ #define Anum_pg_statistic2_sta2op1 11
+ #define Anum_pg_statistic2_sta2op2 12
+ #define Anum_pg_statistic2_sta2op3 13
+ #define Anum_pg_statistic2_sta2op4 14
+ #define Anum_pg_statistic2_sta2numbers1 15
+ #define Anum_pg_statistic2_sta2numbers2 16
+ #define Anum_pg_statistic2_sta2numbers3 17
+ #define Anum_pg_statistic2_sta2numbers4 18
+ #define Anum_pg_statistic2_sta2values1 19
+ #define Anum_pg_statistic2_sta2values2 20
+ #define Anum_pg_statistic2_sta2values3 21
+ #define Anum_pg_statistic2_sta2values4 22
+
+ #if 0
+
+ /*
+ * Currently, three statistical slot "kinds" are defined: most common values,
+ * histogram, and correlation. Additional "kinds" will probably appear in
+ * future to help cope with non-scalar datatypes. Also, custom data types
+ * can define their own "kind" codes by mutual agreement between a custom
+ * typanalyze routine and the selectivity estimation functions of the type's
+ * operators.
+ *
+ * Code reading the pg_statistic2 relation should not assume that a particular
+ * data "kind" will appear in any particular slot. Instead, search the
+ * stakind fields to see if the desired data is available. (The standard
+ * function get_attstatsslot() may be used for this.)
+ */
+
+ /*
+ * The present allocation of "kind" codes is:
+ *
+ * 1-99: reserved for assignment by the core PostgreSQL project
+ * (values in this range will be documented in this file)
+ * 100-199: reserved for assignment by the PostGIS project
+ * (values to be documented in PostGIS documentation)
+ * 200-299: reserved for assignment by the ESRI ST_Geometry project
+ * (values to be documented in ESRI ST_Geometry documentation)
+ * 300-9999: reserved for future public assignments
+ *
+ * For private use you may choose a "kind" code at random in the range
+ * 10000-30000. However, for code that is to be widely disseminated it is
+ * better to obtain a publicly defined "kind" code by request from the
+ * PostgreSQL Global Development Group.
+ */
+
+ /*
+ * In a "most common values" slot, staop is the OID of the "=" operator
+ * used to decide whether values are the same or not. stavalues contains
+ * the K most common non-null values appearing in the column, and stanumbers
+ * contains their frequencies (fractions of total row count). The values
+ * shall be ordered in decreasing frequency. Note that since the arrays are
+ * variable-size, K may be chosen by the statistics collector. Values should
+ * not appear in MCV unless they have been observed to occur more than once;
+ * a unique column will have no MCV slot.
+ */
+ #define STATISTIC_KIND_MCV 1
+
+ /*
+ * A "histogram" slot describes the distribution of scalar data. staop is
+ * the OID of the "<" operator that describes the sort ordering. (In theory,
+ * more than one histogram could appear, if a datatype has more than one
+ * useful sort operator.) stavalues contains M (>=2) non-null values that
+ * divide the non-null column data values into M-1 bins of approximately equal
+ * population. The first stavalues item is the MIN and the last is the MAX.
+ * stanumbers is not used and should be NULL. IMPORTANT POINT: if an MCV
+ * slot is also provided, then the histogram describes the data distribution
+ * *after removing the values listed in MCV* (thus, it's a "compressed
+ * histogram" in the technical parlance). This allows a more accurate
+ * representation of the distribution of a column with some very-common
+ * values. In a column with only a few distinct values, it's possible that
+ * the MCV list describes the entire data population; in this case the
+ * histogram reduces to empty and should be omitted.
+ */
+ #define STATISTIC_KIND_HISTOGRAM 2
+
+ /*
+ * A "correlation" slot describes the correlation between the physical order
+ * of table tuples and the ordering of data values of this column, as seen
+ * by the "<" operator identified by staop. (As with the histogram, more
+ * than one entry could theoretically appear.) stavalues is not used and
+ * should be NULL. stanumbers contains a single entry, the correlation
+ * coefficient between the sequence of data values and the sequence of
+ * their actual tuple positions. The coefficient ranges from +1 to -1.
+ */
+ #define STATISTIC_KIND_CORRELATION 3
+
+ /*
+ * A "most common elements" slot is similar to a "most common values" slot,
+ * except that it stores the most common non-null *elements* of the column
+ * values. This is useful when the column datatype is an array or some other
+ * type with identifiable elements (for instance, tsvector). staop contains
+ * the equality operator appropriate to the element type. stavalues contains
+ * the most common element values, and stanumbers their frequencies. Unlike
+ * MCV slots, the values are sorted into order (to support binary search
+ * for a particular value). Since this puts the minimum and maximum
+ * frequencies at unpredictable spots in stanumbers, there are two extra
+ * members of stanumbers, holding copies of the minimum and maximum
+ * frequencies.
+ *
+ * Note: in current usage for tsvector columns, the stavalues elements are of
+ * type text, even though their representation within tsvector is not
+ * exactly text.
+ */
+ #define STATISTIC_KIND_MCELEM 4
+
+ #endif
+
+ #endif /* PG_STATISTIC2_H */
diff -dcrpN postgresql.orig/src/include/catalog/pg_statistic3.h postgresql/src/include/catalog/pg_statistic3.h
*** postgresql.orig/src/include/catalog/pg_statistic3.h 1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/include/catalog/pg_statistic3.h 2011-04-28 14:21:14.780173533 +0200
***************
*** 0 ****
--- 1,265 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_statistic3.h
+ * definition of the system "expression statistic" relation (pg_statistic3)
+ * along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_statistic3.h
+ *
+ * NOTES
+ * the genbki.pl script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef PG_STATISTIC3_H
+ #define PG_STATISTIC3_H
+
+ #include "catalog/genbki.h"
+
+ /*
+ * The CATALOG definition has to refer to the type of stavaluesN as
+ * "anyarray" so that bootstrap mode recognizes it. There is no real
+ * typedef for that, however. Since the fields are potentially-null and
+ * therefore can't be accessed directly from C code, there is no particular
+ * need for the C struct definition to show a valid field type --- instead
+ * we just make it int.
+ */
+ #define anyarray int
+
+ /* ----------------
+ * pg_statistic3 definition. cpp turns this into
+ * typedef struct FormData_pg_statistic3
+ * ----------------
+ */
+ #define Statistic3RelationId 3073
+
+ CATALOG(pg_statistic3,3073) BKI_WITHOUT_OIDS
+ {
+ /* These fields form the unique key for the entry: */
+ Oid sta3relid; /* relation containing attribute */
+ pg_node_tree sta3expr; /* expression stat is for */
+ bool sta3inherit; /* true if inheritance children are included */
+
+ /* the fraction of the column's entries that are NULL: */
+ float4 sta3nullfrac;
+
+ /*
+ * stawidth is the average width in bytes of non-null entries. For
+ * fixed-width datatypes this is of course the same as the typlen, but for
+ * var-width types it is more useful. Note that this is the average width
+ * of the data as actually stored, post-TOASTing (eg, for a
+ * moved-out-of-line value, only the size of the pointer object is
+ * counted). This is the appropriate definition for the primary use of
+ * the statistic, which is to estimate sizes of in-memory hash tables of
+ * tuples.
+ */
+ int4 sta3width;
+
+ /* ----------------
+ * stadistinct indicates the (approximate) number of distinct non-null
+ * data values in the column. The interpretation is:
+ * 0 unknown or not computed
+ * > 0 actual number of distinct values
+ * < 0 negative of multiplier for number of rows
+ * The special negative case allows us to cope with columns that are
+ * unique (stadistinct = -1) or nearly so (for example, a column in
+ * which values appear about twice on the average could be represented
+ * by stadistinct = -0.5). Because the number-of-rows statistic in
+ * pg_class may be updated more frequently than pg_statistic3 is, it's
+ * important to be able to describe such situations as a multiple of
+ * the number of rows, rather than a fixed number of distinct values.
+ * But in other cases a fixed number is correct (eg, a boolean column).
+ * ----------------
+ */
+ float4 sta3distinct;
+
+ /* ----------------
+ * To allow keeping statistics on different kinds of datatypes,
+ * we do not hard-wire any particular meaning for the remaining
+ * statistical fields. Instead, we provide several "slots" in which
+ * statistical data can be placed. Each slot includes:
+ * kind integer code identifying kind of data
+ * op OID of associated operator, if needed
+ * numbers float4 array (for statistical values)
+ * values anyarray (for representations of data values)
+ * The ID and operator fields are never NULL; they are zeroes in an
+ * unused slot. The numbers and values fields are NULL in an unused
+ * slot, and might also be NULL in a used slot if the slot kind has
+ * no need for one or the other.
+ * ----------------
+ */
+
+ int2 sta3kind1;
+ int2 sta3kind2;
+ int2 sta3kind3;
+ int2 sta3kind4;
+
+ Oid sta3op1;
+ Oid sta3op2;
+ Oid sta3op3;
+ Oid sta3op4;
+
+ /*
+ * THE REST OF THESE ARE VARIABLE LENGTH FIELDS, and may even be absent
+ * (NULL). They cannot be accessed as C struct entries; you have to use
+ * the full field access machinery (heap_getattr) for them. We declare
+ * them here for the catalog machinery.
+ */
+
+ float4 sta3numbers1[1];
+ float4 sta3numbers2[1];
+ float4 sta3numbers3[1];
+ float4 sta3numbers4[1];
+
+ /*
+ * Values in these arrays are values of the column's data type. We
+ * presently have to cheat quite a bit to allow polymorphic arrays of this
+ * kind, but perhaps someday it'll be a less bogus facility.
+ */
+ anyarray sta3values1;
+ anyarray sta3values2;
+ anyarray sta3values3;
+ anyarray sta3values4;
+ } FormData_pg_statistic3;
+
+ #define STATISTIC_NUM_SLOTS 4
+
+ #undef anyarray
+
+
+ /* ----------------
+ * Form_pg_statistic3 corresponds to a pointer to a tuple with
+ * the format of pg_statistic3 relation.
+ * ----------------
+ */
+ typedef FormData_pg_statistic3 *Form_pg_statistic3;
+
+ /* ----------------
+ * compiler constants for pg_statistic3
+ * ----------------
+ */
+ #define Natts_pg_statistic3 22
+ #define Anum_pg_statistic3_sta3relid 1
+ #define Anum_pg_statistic3_sta3expr 2
+ #define Anum_pg_statistic3_sta3inherit 3
+ #define Anum_pg_statistic3_sta3nullfrac 4
+ #define Anum_pg_statistic3_sta3width 5
+ #define Anum_pg_statistic3_sta3distinct 6
+ #define Anum_pg_statistic3_sta3kind1 7
+ #define Anum_pg_statistic3_sta3kind2 8
+ #define Anum_pg_statistic3_sta3kind3 9
+ #define Anum_pg_statistic3_sta3kind4 10
+ #define Anum_pg_statistic3_sta3op1 11
+ #define Anum_pg_statistic3_sta3op2 12
+ #define Anum_pg_statistic3_sta3op3 13
+ #define Anum_pg_statistic3_sta3op4 14
+ #define Anum_pg_statistic3_sta3numbers1 15
+ #define Anum_pg_statistic3_sta3numbers2 16
+ #define Anum_pg_statistic3_sta3numbers3 17
+ #define Anum_pg_statistic3_sta3numbers4 18
+ #define Anum_pg_statistic3_sta3values1 19
+ #define Anum_pg_statistic3_sta3values2 20
+ #define Anum_pg_statistic3_sta3values3 21
+ #define Anum_pg_statistic3_sta3values4 22
+
+ #if 0
+
+ /*
+ * Currently, three statistical slot "kinds" are defined: most common values,
+ * histogram, and correlation. Additional "kinds" will probably appear in
+ * future to help cope with non-scalar datatypes. Also, custom data types
+ * can define their own "kind" codes by mutual agreement between a custom
+ * typanalyze routine and the selectivity estimation functions of the type's
+ * operators.
+ *
+ * Code reading the pg_statistic3 relation should not assume that a particular
+ * data "kind" will appear in any particular slot. Instead, search the
+ * stakind fields to see if the desired data is available. (The standard
+ * function get_attstatsslot() may be used for this.)
+ */
+
+ /*
+ * The present allocation of "kind" codes is:
+ *
+ * 1-99: reserved for assignment by the core PostgreSQL project
+ * (values in this range will be documented in this file)
+ * 100-199: reserved for assignment by the PostGIS project
+ * (values to be documented in PostGIS documentation)
+ * 200-299: reserved for assignment by the ESRI ST_Geometry project
+ * (values to be documented in ESRI ST_Geometry documentation)
+ * 300-9999: reserved for future public assignments
+ *
+ * For private use you may choose a "kind" code at random in the range
+ * 10000-30000. However, for code that is to be widely disseminated it is
+ * better to obtain a publicly defined "kind" code by request from the
+ * PostgreSQL Global Development Group.
+ */
+
+ /*
+ * In a "most common values" slot, staop is the OID of the "=" operator
+ * used to decide whether values are the same or not. stavalues contains
+ * the K most common non-null values appearing in the column, and stanumbers
+ * contains their frequencies (fractions of total row count). The values
+ * shall be ordered in decreasing frequency. Note that since the arrays are
+ * variable-size, K may be chosen by the statistics collector. Values should
+ * not appear in MCV unless they have been observed to occur more than once;
+ * a unique column will have no MCV slot.
+ */
+ #define STATISTIC_KIND_MCV 1
+
+ /*
+ * A "histogram" slot describes the distribution of scalar data. staop is
+ * the OID of the "<" operator that describes the sort ordering. (In theory,
+ * more than one histogram could appear, if a datatype has more than one
+ * useful sort operator.) stavalues contains M (>=2) non-null values that
+ * divide the non-null column data values into M-1 bins of approximately equal
+ * population. The first stavalues item is the MIN and the last is the MAX.
+ * stanumbers is not used and should be NULL. IMPORTANT POINT: if an MCV
+ * slot is also provided, then the histogram describes the data distribution
+ * *after removing the values listed in MCV* (thus, it's a "compressed
+ * histogram" in the technical parlance). This allows a more accurate
+ * representation of the distribution of a column with some very-common
+ * values. In a column with only a few distinct values, it's possible that
+ * the MCV list describes the entire data population; in this case the
+ * histogram reduces to empty and should be omitted.
+ */
+ #define STATISTIC_KIND_HISTOGRAM 2
+
+ /*
+ * A "correlation" slot describes the correlation between the physical order
+ * of table tuples and the ordering of data values of this column, as seen
+ * by the "<" operator identified by staop. (As with the histogram, more
+ * than one entry could theoretically appear.) stavalues is not used and
+ * should be NULL. stanumbers contains a single entry, the correlation
+ * coefficient between the sequence of data values and the sequence of
+ * their actual tuple positions. The coefficient ranges from +1 to -1.
+ */
+ #define STATISTIC_KIND_CORRELATION 3
+
+ /*
+ * A "most common elements" slot is similar to a "most common values" slot,
+ * except that it stores the most common non-null *elements* of the column
+ * values. This is useful when the column datatype is an array or some other
+ * type with identifiable elements (for instance, tsvector). staop contains
+ * the equality operator appropriate to the element type. stavalues contains
+ * the most common element values, and stanumbers their frequencies. Unlike
+ * MCV slots, the values are sorted into order (to support binary search
+ * for a particular value). Since this puts the minimum and maximum
+ * frequencies at unpredictable spots in stanumbers, there are two extra
+ * members of stanumbers, holding copies of the minimum and maximum
+ * frequencies.
+ *
+ * Note: in current usage for tsvector columns, the stavalues elements are of
+ * type text, even though their representation within tsvector is not
+ * exactly text.
+ */
+ #define STATISTIC_KIND_MCELEM 4
+
+ #endif
+
+ #endif /* PG_STATISTIC2_H */
diff -dcrpN postgresql.orig/src/include/commands/defrem.h postgresql/src/include/commands/defrem.h
*** postgresql.orig/src/include/commands/defrem.h 2011-04-11 15:36:27.243806451 +0200
--- postgresql/src/include/commands/defrem.h 2011-04-28 14:21:14.782173399 +0200
*************** extern char *ChooseIndexName(const char
*** 50,55 ****
--- 50,56 ----
bool primary, bool isconstraint);
extern List *ChooseIndexColumnNames(List *indexElems);
extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
+ extern void ExtraStatistics(ExtraStatStmt *stmt);
/* commands/functioncmds.c */
extern void CreateFunction(CreateFunctionStmt *stmt, const char *queryString);
diff -dcrpN postgresql.orig/src/include/nodes/nodes.h postgresql/src/include/nodes/nodes.h
*** postgresql.orig/src/include/nodes/nodes.h 2011-03-22 17:53:48.045903422 +0100
--- postgresql/src/include/nodes/nodes.h 2011-04-28 14:21:14.784173265 +0200
*************** typedef enum NodeTag
*** 362,367 ****
--- 362,368 ----
T_CreateExtensionStmt,
T_AlterExtensionStmt,
T_AlterExtensionContentsStmt,
+ T_ExtraStatStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
diff -dcrpN postgresql.orig/src/include/nodes/parsenodes.h postgresql/src/include/nodes/parsenodes.h
*** postgresql.orig/src/include/nodes/parsenodes.h 2011-04-26 09:54:04.106355573 +0200
--- postgresql/src/include/nodes/parsenodes.h 2011-04-28 14:21:14.789172925 +0200
*************** typedef enum DropBehavior
*** 1160,1165 ****
--- 1160,1178 ----
} DropBehavior;
/* ----------------------
+ * Create Cross Column Statistics
+ * ----------------------
+ */
+ typedef struct ExtraStatStmt
+ {
+ NodeTag type;
+ bool create;
+ RangeVar *relation;
+ List *columns;
+ Node *expr;
+ } ExtraStatStmt;
+
+ /* ----------------------
* Alter Table
* ----------------------
*/
diff -dcrpN postgresql.orig/src/include/parser/kwlist.h postgresql/src/include/parser/kwlist.h
*** postgresql.orig/src/include/parser/kwlist.h 2011-03-18 13:11:36.826637445 +0100
--- postgresql/src/include/parser/kwlist.h 2011-04-28 14:21:14.790172858 +0200
*************** PG_KEYWORD("exclusive", EXCLUSIVE, UNRES
*** 148,153 ****
--- 148,154 ----
PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
+ PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
diff -dcrpN postgresql.orig/src/include/parser/parse_utilcmd.h postgresql/src/include/parser/parse_utilcmd.h
*** postgresql.orig/src/include/parser/parse_utilcmd.h 2011-01-04 15:13:16.163549374 +0100
--- postgresql/src/include/parser/parse_utilcmd.h 2011-04-28 14:21:14.792172725 +0200
*************** extern void transformRuleStmt(RuleStmt *
*** 25,28 ****
--- 25,33 ----
List **actions, Node **whereClause);
extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
+ extern ExtraStatStmt *transformExtraStatistics(ExtraStatStmt *stmt,
+ const char *queryString);
+
+ extern bool set_location_unknown_walker(Node *node, void *context);
+
#endif /* PARSE_UTILCMD_H */
diff -dcrpN postgresql.orig/src/include/utils/lsyscache.h postgresql/src/include/utils/lsyscache.h
*** postgresql.orig/src/include/utils/lsyscache.h 2011-04-11 15:36:27.256805539 +0200
--- postgresql/src/include/utils/lsyscache.h 2011-04-28 14:21:14.793172658 +0200
***************
*** 16,21 ****
--- 16,22 ----
#include "access/attnum.h"
#include "access/htup.h"
#include "nodes/pg_list.h"
+ #include "utils/selfuncs.h"
/* I/O function selector for get_type_io_data */
typedef enum IOFuncSelector
*************** extern Oid getBaseType(Oid typid);
*** 131,137 ****
extern Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod);
extern int32 get_typavgwidth(Oid typid, int32 typmod);
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
! extern bool get_attstatsslot(HeapTuple statstuple,
Oid atttype, int32 atttypmod,
int reqkind, Oid reqop,
Oid *actualop,
--- 132,139 ----
extern Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod);
extern int32 get_typavgwidth(Oid typid, int32 typmod);
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
!
! extern bool get_attstatsslot(HeapTuple statstuple, StatType stat_type,
Oid atttype, int32 atttypmod,
int reqkind, Oid reqop,
Oid *actualop,
diff -dcrpN postgresql.orig/src/include/utils/selfuncs.h postgresql/src/include/utils/selfuncs.h
*** postgresql.orig/src/include/utils/selfuncs.h 2011-04-13 10:11:05.060214051 +0200
--- postgresql/src/include/utils/selfuncs.h 2011-04-28 14:21:14.795172522 +0200
***************
*** 62,75 ****
p = 1.0; \
} while (0)
/* Return data from examine_variable and friends */
typedef struct VariableStatData
{
Node *var; /* the Var or expression tree */
RelOptInfo *rel; /* Relation, or NULL if not identifiable */
! HeapTuple statsTuple; /* pg_statistic tuple, or NULL if none */
! /* NB: if statsTuple!=NULL, it must be freed when caller is done */
void (*freefunc) (HeapTuple tuple); /* how to free statsTuple */
Oid vartype; /* exposed type of expression */
Oid atttype; /* type to pass to get_attstatsslot */
--- 62,81 ----
p = 1.0; \
} while (0)
+ typedef enum StatType {
+ STAT_VARIABLE,
+ STAT_EXPRESSION
+ } StatType;
/* Return data from examine_variable and friends */
typedef struct VariableStatData
{
Node *var; /* the Var or expression tree */
RelOptInfo *rel; /* Relation, or NULL if not identifiable */
! StatType stats_type;
! HeapTuple statsTuple; /* pg_statistic or pg_statistic3 tuple depending on stats_type
! * or NULL if none */
! /* NB: if statsTuple!=NULL || stats3Tuple!=NULL, it must be freed when caller is done */
void (*freefunc) (HeapTuple tuple); /* how to free statsTuple */
Oid vartype; /* exposed type of expression */
Oid atttype; /* type to pass to get_attstatsslot */
diff -dcrpN postgresql.orig/src/include/utils/syscache.h postgresql/src/include/utils/syscache.h
*** postgresql.orig/src/include/utils/syscache.h 2011-02-10 10:36:32.352678334 +0100
--- postgresql/src/include/utils/syscache.h 2011-04-28 14:21:14.796172454 +0200
*************** enum SysCacheIdentifier
*** 73,78 ****
--- 73,79 ----
RELNAMENSP,
RELOID,
RULERELNAME,
+ STAT3RELEXPRINH,
STATRELATTINH,
TABLESPACEOID,
TSCONFIGMAP,
diff -dcrpN postgresql.orig/src/test/regress/expected/sanity_check.out postgresql/src/test/regress/expected/sanity_check.out
*** postgresql.orig/src/test/regress/expected/sanity_check.out 2011-02-10 10:36:32.374676822 +0100
--- postgresql/src/test/regress/expected/sanity_check.out 2011-04-28 14:21:14.797172386 +0200
*************** SELECT relname, relhasindex
*** 121,126 ****
--- 121,128 ----
pg_shdepend | t
pg_shdescription | t
pg_statistic | t
+ pg_statistic2 | t
+ pg_statistic3 | t
pg_tablespace | t
pg_trigger | t
pg_ts_config | t
*************** SELECT relname, relhasindex
*** 157,163 ****
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (146 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 159,165 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (148 rows)
--
-- another sanity check: every system catalog that has OIDs should have