diff -dcrpN postgresql.orig/src/backend/access/common/tupdesc.c postgresql.4/src/backend/access/common/tupdesc.c *** postgresql.orig/src/backend/access/common/tupdesc.c 2011-07-18 15:42:00.008379772 +0200 --- postgresql.4/src/backend/access/common/tupdesc.c 2011-08-02 11:49:16.452381480 +0200 *************** equalTupleDescs(TupleDesc tupdesc1, Tupl *** 337,344 **** return false; if (attr1->atttypid != attr2->atttypid) return false; - if (attr1->attstattarget != attr2->attstattarget) - return false; if (attr1->attlen != attr2->attlen) return false; if (attr1->attndims != attr2->attndims) --- 337,342 ---- *************** TupleDescInitEntry(TupleDesc desc, *** 471,477 **** else MemSet(NameStr(att->attname), 0, NAMEDATALEN); - att->attstattarget = -1; att->attcacheoff = -1; att->atttypmod = typmod; --- 469,474 ---- diff -dcrpN postgresql.orig/src/backend/access/nbtree/nbtcompare.c postgresql.4/src/backend/access/nbtree/nbtcompare.c *** postgresql.orig/src/backend/access/nbtree/nbtcompare.c 2011-01-04 15:13:15.816567224 +0100 --- postgresql.4/src/backend/access/nbtree/nbtcompare.c 2011-07-27 15:13:09.756534651 +0200 *************** btoidvectorcmp(PG_FUNCTION_ARGS) *** 220,225 **** --- 220,249 ---- } Datum + btint2vectorcmp(PG_FUNCTION_ARGS) + { + int2vector *a = (int2vector *) PG_GETARG_POINTER(0); + int2vector *b = (int2vector *) PG_GETARG_POINTER(1); + int i; + + /* We arbitrarily choose to sort first by vector length */ + if (a->dim1 != b->dim1) + PG_RETURN_INT32(a->dim1 - b->dim1); + + for (i = 0; i < a->dim1; i++) + { + if (a->values[i] != b->values[i]) + { + if (a->values[i] > b->values[i]) + PG_RETURN_INT32(1); + else + PG_RETURN_INT32(-1); + } + } + PG_RETURN_INT32(0); + } + + Datum btcharcmp(PG_FUNCTION_ARGS) { char a = PG_GETARG_CHAR(0); diff -dcrpN postgresql.orig/src/backend/bootstrap/bootstrap.c postgresql.4/src/backend/bootstrap/bootstrap.c *** postgresql.orig/src/backend/bootstrap/bootstrap.c 2011-07-18 15:42:00.015379264 +0200 --- postgresql.4/src/backend/bootstrap/bootstrap.c 2011-08-02 11:49:16.481379350 +0200 *************** DefineAttr(char *name, char *type, int a *** 736,742 **** attrtypes[attnum]->attndims = 0; } - attrtypes[attnum]->attstattarget = -1; attrtypes[attnum]->attcacheoff = -1; attrtypes[attnum]->atttypmod = -1; attrtypes[attnum]->attislocal = true; --- 736,741 ---- diff -dcrpN postgresql.orig/src/backend/catalog/heap.c postgresql.4/src/backend/catalog/heap.c *** postgresql.orig/src/backend/catalog/heap.c 2011-07-24 18:16:45.258679387 +0200 --- postgresql.4/src/backend/catalog/heap.c 2011-08-02 11:59:09.568791478 +0200 *************** static List *insert_ordered_unique_oid(L *** 132,168 **** */ static FormData_pg_attribute a1 = { ! 0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData), SelfItemPointerAttributeNumber, 0, -1, -1, false, 'p', 's', true, false, false, true, 0 }; static FormData_pg_attribute a2 = { ! 0, {"oid"}, OIDOID, 0, sizeof(Oid), ObjectIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a3 = { ! 0, {"xmin"}, XIDOID, 0, sizeof(TransactionId), MinTransactionIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a4 = { ! 0, {"cmin"}, CIDOID, 0, sizeof(CommandId), MinCommandIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a5 = { ! 0, {"xmax"}, XIDOID, 0, sizeof(TransactionId), MaxTransactionIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a6 = { ! 0, {"cmax"}, CIDOID, 0, sizeof(CommandId), MaxCommandIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; --- 132,168 ---- */ static FormData_pg_attribute a1 = { ! 0, {"ctid"}, TIDOID, sizeof(ItemPointerData), SelfItemPointerAttributeNumber, 0, -1, -1, false, 'p', 's', true, false, false, true, 0 }; static FormData_pg_attribute a2 = { ! 0, {"oid"}, OIDOID, sizeof(Oid), ObjectIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a3 = { ! 0, {"xmin"}, XIDOID, sizeof(TransactionId), MinTransactionIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a4 = { ! 0, {"cmin"}, CIDOID, sizeof(CommandId), MinCommandIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a5 = { ! 0, {"xmax"}, XIDOID, sizeof(TransactionId), MaxTransactionIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a6 = { ! 0, {"cmax"}, CIDOID, sizeof(CommandId), MaxCommandIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; *************** static FormData_pg_attribute a6 = { *** 174,180 **** * used in SQL. */ static FormData_pg_attribute a7 = { ! 0, {"tableoid"}, OIDOID, 0, sizeof(Oid), TableOidAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; --- 174,180 ---- * used in SQL. */ static FormData_pg_attribute a7 = { ! 0, {"tableoid"}, OIDOID, sizeof(Oid), TableOidAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }; *************** InsertPgAttributeTuple(Relation pg_attri *** 601,607 **** values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_attribute->attrelid); values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname); values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid); - values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget); values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen); values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum); values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims); --- 601,606 ---- *************** AddNewAttributeTuples(Oid new_rel_oid, *** 672,683 **** attr = tupdesc->attrs[i]; /* Fill in the correct relation OID */ attr->attrelid = new_rel_oid; ! /* Make sure these are OK, too */ ! attr->attstattarget = -1; attr->attcacheoff = -1; InsertPgAttributeTuple(rel, attr, indstate); /* Add dependency info */ myself.classId = RelationRelationId; myself.objectId = new_rel_oid; --- 671,683 ---- attr = tupdesc->attrs[i]; /* Fill in the correct relation OID */ attr->attrelid = new_rel_oid; ! /* Make sure this is OK, too */ attr->attcacheoff = -1; InsertPgAttributeTuple(rel, attr, indstate); + AddStatistics(new_rel_oid, &attr->attnum, 1, (oidinhcount > 0), -1); + /* Add dependency info */ myself.classId = RelationRelationId; myself.objectId = new_rel_oid; *************** RemoveAttributeById(Oid relid, AttrNumbe *** 1491,1499 **** /* Remove any NOT NULL constraint the column may have */ attStruct->attnotnull = false; - /* We don't want to keep stats for it anymore */ - attStruct->attstattarget = 0; - /* * Change the column name to something that isn't likely to conflict */ --- 1491,1496 ---- *************** RemoveAttributeById(Oid relid, AttrNumbe *** 1515,1522 **** heap_close(attr_rel, RowExclusiveLock); if (attnum > 0) ! RemoveStatistics(relid, attnum); relation_close(rel, NoLock); } --- 1512,1520 ---- heap_close(attr_rel, RowExclusiveLock); + /* Only drop pg_statistic entries for non system columns. */ if (attnum > 0) ! RemoveStatistics(relid, &attnum, 1); relation_close(rel, NoLock); } *************** heap_drop_with_catalog(Oid relid) *** 1740,1746 **** /* * delete statistics */ ! RemoveStatistics(relid, 0); /* * delete attribute tuples --- 1738,1744 ---- /* * delete statistics */ ! RemoveStatistics(relid, NULL, 0); /* * delete attribute tuples *************** cookConstraint(ParseState *pstate, *** 2521,2539 **** /* ! * RemoveStatistics --- remove entries in pg_statistic for a rel or column * ! * If attnum is zero, remove all entries for rel; else remove only the one(s) ! * for that column. */ void ! RemoveStatistics(Oid relid, AttrNumber attnum) { Relation pgstatistic; SysScanDesc scan; ScanKeyData key[2]; int nkeys; HeapTuple tuple; pgstatistic = heap_open(StatisticRelationId, RowExclusiveLock); --- 2519,2735 ---- /* ! * AddStatistics --- add an entry in pg_statistic * ! * attnums - an ordered array of AttrNumbers ! * n_attnum - number of elements in the array ! * statistics_target - the sampling size for this statistics ! * ! * Entries in pg_statistic are used by the planner to collect selectivity values. ! * This function is called when a new relation is created or a new column is added ! * to a relation. It is therefore ensured that every column has an entry during the ! * lifetime of the relation since its creation. There is one exception from under ! * this rule: thus function is a no-op during bootstrapping to avoid a catch-22 ! * situation where a pg_statistic entry would be created when pg_statistic itself ! * doesn't exist yet. pg_statistic entries for system tables will be created by ! * ANALYZE as before. The entry is created as invalid (stavalid == false) and ! * the histogram columns are NULLs. This will also be fixed by ANALYZE. */ void ! AddStatistics(Oid relid, AttrNumber *attnums, int n_attnums, bool inherited, int statistics_target) ! { ! Relation rel; ! ScanKeyData scanKey[2]; ! SysScanDesc scan; ! int2vector *attnumvector; ! HeapTuple tuple; ! TupleDesc tupDesc; ! Datum values[Natts_pg_statistic]; ! bool nulls[Natts_pg_statistic]; ! int i, j; ! ! if (IsBootstrapProcessingMode()) ! return; ! ! Assert(attnums != NULL); ! Assert(n_attnums > 0); ! ! attnumvector = buildint2vector(attnums, n_attnums); ! ! rel = heap_open(StatisticRelationId, RowExclusiveLock); ! ! ScanKeyInit(&scanKey[0], ! Anum_pg_statistic_starelid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(relid)); ! ScanKeyInit(&scanKey[1], ! Anum_pg_statistic_staattnums, ! BTEqualStrategyNumber, F_ARRAY_EQ, ! PointerGetDatum(attnumvector)); ! ! scan = systable_beginscan(rel, StatisticRelidAttnumsInhIndexId, true, ! SnapshotNow, 2, scanKey); ! ! tuple = systable_getnext(scan); ! if (HeapTupleIsValid(tuple)) ! { ! systable_endscan(scan); ! elog(ERROR, "pg_statistic entry already exists for this table and set of columns"); ! } ! ! systable_endscan(scan); ! ! for (i = 0; i < Natts_pg_statistic; i++) ! nulls[i] = true; ! ! i = 0; ! values[i] = ObjectIdGetDatum(relid); nulls[i++] = false; /* starelid */ ! values[i] = BoolGetDatum(inherited); nulls[i++] = false; /* stainherit */ ! values[i] = BoolGetDatum(false); nulls[i++] = false; /* stavalid */ ! values[i] = Int32GetDatum(statistics_target); nulls[i++] = false; /* statarget */ ! values[i] = Float4GetDatum(0); nulls[i++] = false; /* stanullfrac */ ! values[i] = Int32GetDatum(0); nulls[i++] = false; /* stawidth */ ! values[i] = Float4GetDatum(0); nulls[i++] = false; /* stadistinct */ ! for (j = 0; j < STATISTIC_NUM_SLOTS; j++) ! { ! values[i] = Int16GetDatum(0); nulls[i++] = false; /* stakindN */ ! } ! for (j = 0; j < STATISTIC_NUM_SLOTS; j++) ! { ! values[i] = ObjectIdGetDatum(0); nulls[i++] = false; /* staopN */ ! } ! values[i] = PointerGetDatum(attnumvector); nulls[i++] = false; /* stainherit */ ! ! tupDesc = RelationGetDescr(rel); ! ! tuple = heap_form_tuple(tupDesc, values, nulls); ! ! simple_heap_insert(rel, tuple); ! ! CatalogUpdateIndexes(rel, tuple); ! ! pfree(attnumvector); ! ! relation_close(rel, RowExclusiveLock); ! } ! ! typedef struct invalidate_stats { ! HeapTuple tuple; ! struct invalidate_stats *next; ! } invalidate_stats; ! ! /* ! * InvalidateStatistics --- invalidate all pg_statistic entries of this attnum ! * ! * We need to collect copies of tuples that need invalidating in order not to ! * conflict with the system table scan. ! */ ! void ! InvalidateStatistics(Oid relid, AttrNumber attnum) ! { ! Relation rel; ! ScanKeyData scanKey; ! SysScanDesc scan; ! HeapTuple tuple; ! TupleDesc tupDesc; ! Form_pg_statistic stattuple; ! invalidate_stats *tupptr; ! invalidate_stats *tupptr_next; ! int i; ! ! if (IsBootstrapProcessingMode()) ! return; ! ! Assert(attnums != NULL); ! Assert(n_attnums > 0); ! ! rel = heap_open(StatisticRelationId, RowExclusiveLock); ! tupDesc = RelationGetDescr(rel); ! ! ScanKeyInit(&scanKey, ! Anum_pg_statistic_starelid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(relid)); ! ! scan = systable_beginscan(rel, StatisticRelidAttnumsInhIndexId, true, ! SnapshotNow, 1, &scanKey); ! ! ! tupptr = tupptr_next = NULL; ! while (HeapTupleIsValid(tuple = systable_getnext(scan))) ! { ! bool isnull; ! Datum attnvec; ! int2vector *attnumvector; ! ! attnvec = heap_getattr(tuple, Anum_pg_statistic_staattnums, tupDesc, &isnull); ! ! Assert(!isnull); ! ! attnumvector = (int2vector *) DatumGetPointer(attnvec); ! ! for (i = 0; i < attnumvector->dim1; i++) ! { ! if (attnumvector->values[i] == attnum) ! { ! invalidate_stats *tmp; ! ! ! tmp = palloc(sizeof(invalidate_stats)); ! tmp->tuple = heap_copytuple(tuple); ! tmp->next = NULL; ! ! if (tupptr == NULL) ! tupptr = tupptr_next = tmp; ! else ! { ! tupptr_next->next = tmp; ! tupptr_next = tmp; ! } ! ! break; /* find next tuple */ ! } ! } ! } ! ! systable_endscan(scan); ! ! while (tupptr) ! { ! stattuple = (Form_pg_statistic) GETSTRUCT(tupptr->tuple); ! ! stattuple->stavalid = false; ! ! simple_heap_update(rel, &tupptr->tuple->t_self, tupptr->tuple); ! ! CatalogUpdateIndexes(rel, tupptr->tuple); ! ! tupptr_next = tupptr->next; ! ! heap_freetuple(tupptr->tuple); ! pfree(tupptr); ! ! tupptr = tupptr_next; ! } ! ! relation_close(rel, RowExclusiveLock); ! } ! ! /* ! * RemoveStatistics --- remove entries in pg_statistic for a rel's set of columns ! * ! * If attnums is NULL, remove all entries for rel; else remove only the one ! * for that set of column(s). ! */ ! void ! RemoveStatistics(Oid relid, AttrNumber *attnums, int n_attnums) { Relation pgstatistic; SysScanDesc scan; ScanKeyData key[2]; int nkeys; HeapTuple tuple; + int2vector *attnumvector = NULL; pgstatistic = heap_open(StatisticRelationId, RowExclusiveLock); *************** RemoveStatistics(Oid relid, AttrNumber a *** 2542,2559 **** BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); ! if (attnum == 0) nkeys = 1; else { ScanKeyInit(&key[1], ! Anum_pg_statistic_staattnum, ! BTEqualStrategyNumber, F_INT2EQ, ! Int16GetDatum(attnum)); nkeys = 2; } ! scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true, SnapshotNow, nkeys, key); /* we must loop even when attnum != 0, in case of inherited stats */ --- 2738,2756 ---- BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); ! if (attnums == NULL) nkeys = 1; else { + attnumvector = buildint2vector(attnums, n_attnums); ScanKeyInit(&key[1], ! Anum_pg_statistic_staattnums, ! BTEqualStrategyNumber, F_INT2VECTOREQ, ! PointerGetDatum(attnumvector)); nkeys = 2; } ! scan = systable_beginscan(pgstatistic, StatisticRelidAttnumsInhIndexId, true, SnapshotNow, nkeys, key); /* we must loop even when attnum != 0, in case of inherited stats */ *************** RemoveStatistics(Oid relid, AttrNumber a *** 2562,2567 **** --- 2759,2767 ---- systable_endscan(scan); + if (attnumvector) + pfree(attnumvector); + heap_close(pgstatistic, RowExclusiveLock); } diff -dcrpN postgresql.orig/src/backend/catalog/index.c postgresql.4/src/backend/catalog/index.c *** postgresql.orig/src/backend/catalog/index.c 2011-07-24 18:16:45.259679336 +0200 --- postgresql.4/src/backend/catalog/index.c 2011-08-02 11:49:16.512377071 +0200 *************** ConstructTupleDescriptor(Relation heapRe *** 347,353 **** */ to->attnum = i + 1; - to->attstattarget = -1; to->attcacheoff = -1; to->attnotnull = false; to->atthasdef = false; --- 347,352 ---- *************** ConstructTupleDescriptor(Relation heapRe *** 385,391 **** to->attbyval = typeTup->typbyval; to->attstorage = typeTup->typstorage; to->attalign = typeTup->typalign; - to->attstattarget = -1; to->attcacheoff = -1; to->atttypmod = -1; to->attislocal = true; --- 384,389 ---- *************** index_drop(Oid indexId) *** 1357,1363 **** * them. */ if (hasexprs) ! RemoveStatistics(indexId, 0); /* * fix ATTRIBUTE relation --- 1355,1361 ---- * them. */ if (hasexprs) ! RemoveStatistics(indexId, NULL, 0); /* * fix ATTRIBUTE relation diff -dcrpN postgresql.orig/src/backend/catalog/system_views.sql postgresql.4/src/backend/catalog/system_views.sql *** postgresql.orig/src/backend/catalog/system_views.sql 2011-07-24 18:16:45.262679185 +0200 --- postgresql.4/src/backend/catalog/system_views.sql 2011-07-27 15:33:44.392554069 +0200 *************** CREATE VIEW pg_stats AS *** 141,147 **** WHEN stakind4 = 3 THEN stanumbers4[1] END AS correlation FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid) ! JOIN pg_attribute a ON (c.oid = attrelid AND attnum = s.staattnum) LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace) WHERE NOT attisdropped AND has_column_privilege(c.oid, a.attnum, 'select'); --- 141,147 ---- WHEN stakind4 = 3 THEN stanumbers4[1] END AS correlation FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid) ! JOIN pg_attribute a ON (c.oid = attrelid AND array_length(s.staattnums, 1) = 1 AND attnum = s.staattnums[0]) LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace) WHERE NOT attisdropped AND has_column_privilege(c.oid, a.attnum, 'select'); diff -dcrpN postgresql.orig/src/backend/commands/analyze.c postgresql.4/src/backend/commands/analyze.c *** postgresql.orig/src/backend/commands/analyze.c 2011-06-20 10:11:35.729661282 +0200 --- postgresql.4/src/backend/commands/analyze.c 2011-08-02 11:51:06.071322632 +0200 *************** *** 42,47 **** --- 42,48 ---- #include "storage/procarray.h" #include "utils/acl.h" #include "utils/attoptcache.h" + #include "utils/builtins.h" #include "utils/datum.h" #include "utils/guc.h" #include "utils/lsyscache.h" *************** static void compute_index_stats(Relation *** 93,99 **** AnlIndexData *indexdata, int nindexes, HeapTuple *rows, int numrows, MemoryContext col_context); ! static VacAttrStats *examine_attribute(Relation onerel, int attnum, Node *index_expr); static int acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows); --- 94,100 ---- AnlIndexData *indexdata, int nindexes, HeapTuple *rows, int numrows, MemoryContext col_context); ! static VacAttrStats *examine_attribute(Relation onerel, AttrNumber attnum, Node *index_expr); static int acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows); *************** compute_index_stats(Relation onerel, dou *** 792,797 **** --- 793,827 ---- } /* + * statistics_target -- returns pg_statistic.statarget + */ + static int4 + statistics_target(Oid relid, AttrNumber *attnums, int n_attnums, bool inherited) + { + int2vector *attnumvector; + HeapTuple tuple; + int4 statarget = -1; /* default */ + + attnumvector = buildint2vector(attnums, n_attnums); + tuple = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(relid), + PointerGetDatum(attnumvector), + BoolGetDatum(inherited)); + if (HeapTupleIsValid(tuple)) + { + Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(tuple); + + if (stats->stavalid) + statarget = stats->statarget; + + ReleaseSysCache(tuple); + } + + return statarget; + } + + + /* * examine_attribute -- pre-analysis of a single column * * Determine whether the column is analyzable; if so, create and initialize *************** compute_index_stats(Relation onerel, dou *** 801,810 **** * and index_expr is the expression tree representing the column's data. */ static VacAttrStats * ! examine_attribute(Relation onerel, int attnum, Node *index_expr) { Form_pg_attribute attr = onerel->rd_att->attrs[attnum - 1]; HeapTuple typtuple; VacAttrStats *stats; int i; bool ok; --- 831,841 ---- * and index_expr is the expression tree representing the column's data. */ static VacAttrStats * ! examine_attribute(Relation onerel, AttrNumber attnum, Node *index_expr) { Form_pg_attribute attr = onerel->rd_att->attrs[attnum - 1]; HeapTuple typtuple; + int4 statarget; VacAttrStats *stats; int i; bool ok; *************** examine_attribute(Relation onerel, int a *** 814,820 **** return NULL; /* Don't analyze column if user has specified not to */ ! if (attr->attstattarget == 0) return NULL; /* --- 845,852 ---- return NULL; /* Don't analyze column if user has specified not to */ ! statarget = statistics_target(onerel->rd_id, &attnum, 1, onerel->rd_att->attrs[attnum - 1]->attinhcount > 0); ! if (statarget == 0) return NULL; /* *************** examine_attribute(Relation onerel, int a *** 823,828 **** --- 855,861 ---- */ stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats)); stats->attr = (Form_pg_attribute) palloc(ATTRIBUTE_FIXED_PART_SIZE); + stats->statarget = stats->oldtarget = statarget; memcpy(stats->attr, attr, ATTRIBUTE_FIXED_PART_SIZE); /* *************** update_attstats(Oid relid, bool inh, int *** 1573,1578 **** --- 1606,1612 ---- int i, k, n; + int2vector *attnumvector = NULL; Datum values[Natts_pg_statistic]; bool nulls[Natts_pg_statistic]; bool replaces[Natts_pg_statistic]; *************** update_attstats(Oid relid, bool inh, int *** 1591,1598 **** } values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(relid); - values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(stats->attr->attnum); values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(inh); values[Anum_pg_statistic_stanullfrac - 1] = Float4GetDatum(stats->stanullfrac); values[Anum_pg_statistic_stawidth - 1] = Int32GetDatum(stats->stawidth); values[Anum_pg_statistic_stadistinct - 1] = Float4GetDatum(stats->stadistinct); --- 1625,1633 ---- } values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(relid); values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(inh); + values[Anum_pg_statistic_stavalid] = BoolGetDatum(true); + values[Anum_pg_statistic_statarget] = Int32GetDatum(stats->oldtarget); values[Anum_pg_statistic_stanullfrac - 1] = Float4GetDatum(stats->stanullfrac); values[Anum_pg_statistic_stawidth - 1] = Int32GetDatum(stats->stawidth); values[Anum_pg_statistic_stadistinct - 1] = Float4GetDatum(stats->stadistinct); *************** update_attstats(Oid relid, bool inh, int *** 1606,1611 **** --- 1641,1650 ---- { values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */ } + + attnumvector = buildint2vector(&(stats->attr->attnum), 1); + values[Anum_pg_statistic_staattnums - 1] = PointerGetDatum(attnumvector); /* staattnums */ + i = Anum_pg_statistic_stanumbers1 - 1; for (k = 0; k < STATISTIC_NUM_SLOTS; k++) { *************** update_attstats(Oid relid, bool inh, int *** 1655,1661 **** /* Is there already a pg_statistic tuple for this attribute? */ oldtup = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(relid), ! Int16GetDatum(stats->attr->attnum), BoolGetDatum(inh)); if (HeapTupleIsValid(oldtup)) --- 1694,1700 ---- /* Is there already a pg_statistic tuple for this attribute? */ oldtup = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(relid), ! PointerGetDatum(attnumvector), BoolGetDatum(inh)); if (HeapTupleIsValid(oldtup)) *************** update_attstats(Oid relid, bool inh, int *** 1676,1681 **** --- 1715,1722 ---- simple_heap_insert(sd, stup); } + pfree(attnumvector); + /* update indexes too */ CatalogUpdateIndexes(sd, stup); *************** static int compare_mcvs(const void *a, c *** 1791,1805 **** static bool std_typanalyze(VacAttrStats *stats) { - Form_pg_attribute attr = stats->attr; Oid ltopr; Oid eqopr; StdAnalyzeData *mystats; ! /* If the attstattarget column is negative, use the default value */ /* NB: it is okay to scribble on stats->attr since it's a copy */ ! if (attr->attstattarget < 0) ! attr->attstattarget = default_statistics_target; /* Look for default "<" and "=" operators for column's type */ get_sort_group_operators(stats->attrtypid, --- 1832,1845 ---- static bool std_typanalyze(VacAttrStats *stats) { Oid ltopr; Oid eqopr; StdAnalyzeData *mystats; ! /* If the statarget column is negative, use the default value */ /* NB: it is okay to scribble on stats->attr since it's a copy */ ! if (stats->statarget < 0) ! stats->statarget = default_statistics_target; /* Look for default "<" and "=" operators for column's type */ get_sort_group_operators(stats->attrtypid, *************** std_typanalyze(VacAttrStats *stats) *** 1844,1857 **** * know it at this point. *-------------------- */ ! stats->minrows = 300 * attr->attstattarget; } else { /* Can't do much but the minimal stuff */ stats->compute_stats = compute_minimal_stats; /* Might as well use the same minrows as above */ ! stats->minrows = 300 * attr->attstattarget; } return true; --- 1884,1897 ---- * know it at this point. *-------------------- */ ! stats->minrows = 300 * stats->statarget; } else { /* Can't do much but the minimal stuff */ stats->compute_stats = compute_minimal_stats; /* Might as well use the same minrows as above */ ! stats->minrows = 300 * stats->statarget; } return true; *************** compute_minimal_stats(VacAttrStatsP stat *** 1896,1902 **** TrackItem *track; int track_cnt, track_max; ! int num_mcv = stats->attr->attstattarget; StdAnalyzeData *mystats = (StdAnalyzeData *) stats->extra_data; /* --- 1936,1942 ---- TrackItem *track; int track_cnt, track_max; ! int num_mcv = stats->statarget; StdAnalyzeData *mystats = (StdAnalyzeData *) stats->extra_data; /* *************** compute_scalar_stats(VacAttrStatsP stats *** 2223,2230 **** int *tupnoLink; ScalarMCVItem *track; int track_cnt = 0; ! int num_mcv = stats->attr->attstattarget; ! int num_bins = stats->attr->attstattarget; StdAnalyzeData *mystats = (StdAnalyzeData *) stats->extra_data; values = (ScalarItem *) palloc(samplerows * sizeof(ScalarItem)); --- 2263,2270 ---- int *tupnoLink; ScalarMCVItem *track; int track_cnt = 0; ! int num_mcv = stats->statarget; ! int num_bins = stats->statarget; StdAnalyzeData *mystats = (StdAnalyzeData *) stats->extra_data; values = (ScalarItem *) palloc(samplerows * sizeof(ScalarItem)); diff -dcrpN postgresql.orig/src/backend/commands/tablecmds.c postgresql.4/src/backend/commands/tablecmds.c *** postgresql.orig/src/backend/commands/tablecmds.c 2011-07-24 18:16:45.267678934 +0200 --- postgresql.4/src/backend/commands/tablecmds.c 2011-08-02 11:49:16.568372952 +0200 *************** *** 35,40 **** --- 35,41 ---- #include "catalog/pg_inherits_fn.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" + #include "catalog/pg_statistic.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" *************** ATExecAddColumn(List **wqueue, AlteredTa *** 4319,4325 **** attribute.attrelid = myrelid; namestrcpy(&(attribute.attname), colDef->colname); attribute.atttypid = typeOid; - attribute.attstattarget = (newattnum > 0) ? -1 : 0; attribute.attlen = tform->typlen; attribute.attcacheoff = -1; attribute.atttypmod = typmod; --- 4320,4325 ---- *************** ATExecAddColumn(List **wqueue, AlteredTa *** 4481,4486 **** --- 4481,4488 ---- add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid); add_column_collation_dependency(myrelid, newattnum, attribute.attcollation); + AddStatistics(myrelid, &attribute.attnum, 1, attribute.attinhcount, (newattnum > 0) ? -1 : 0); + /* * Propagate to children as appropriate. Unlike most other ALTER * routines, we have to do this one level of recursion at a time; we can't *************** ATExecSetStatistics(Relation rel, const *** 4817,4824 **** --- 4819,4832 ---- { int newtarget; Relation attrelation; + Relation statsrelation; + Oid relid; HeapTuple tuple; Form_pg_attribute attrtuple; + AttrNumber attnum; + bool inherited; + int2vector *attnumvector; + Form_pg_statistic stattuple; Assert(IsA(newValue, Integer)); newtarget = intVal(newValue); *************** ATExecSetStatistics(Relation rel, const *** 4844,4850 **** attrelation = heap_open(AttributeRelationId, RowExclusiveLock); ! tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName); if (!HeapTupleIsValid(tuple)) ereport(ERROR, --- 4852,4860 ---- attrelation = heap_open(AttributeRelationId, RowExclusiveLock); ! relid = RelationGetRelid(rel); ! ! tuple = SearchSysCacheAttName(relid, colName); if (!HeapTupleIsValid(tuple)) ereport(ERROR, *************** ATExecSetStatistics(Relation rel, const *** 4859,4874 **** errmsg("cannot alter system column \"%s\"", colName))); ! attrtuple->attstattarget = newtarget; ! simple_heap_update(attrelation, &tuple->t_self, tuple); ! /* keep system catalog indexes current */ ! CatalogUpdateIndexes(attrelation, tuple); ! heap_freetuple(tuple); ! heap_close(attrelation, RowExclusiveLock); } static void --- 4869,4909 ---- errmsg("cannot alter system column \"%s\"", colName))); ! attnum = attrtuple->attnum; ! inherited = (attrtuple->attinhcount > 0); ! ReleaseSysCache(tuple); ! heap_close(attrelation, RowExclusiveLock); ! statsrelation = heap_open(StatisticRelationId, RowExclusiveLock); ! attnumvector = buildint2vector(&attnum, 1); ! ! tuple = SearchSysCacheCopy3(STATRELATTINH, ! ObjectIdGetDatum(relid), ! PointerGetDatum(attnumvector), ! BoolGetDatum(inherited)); ! ! pfree(attnumvector); ! ! if (!HeapTupleIsValid(tuple)) ! AddStatistics(relid, &attnum, 1, inherited, newtarget); ! else ! { ! stattuple = (Form_pg_statistic) GETSTRUCT(tuple); ! ! stattuple->statarget = newtarget; ! ! simple_heap_update(statsrelation, &tuple->t_self, tuple); ! ! /* keep system catalog indexes current */ ! CatalogUpdateIndexes(statsrelation, tuple); ! ! heap_freetuple(tuple); ! } ! ! heap_close(statsrelation, RowExclusiveLock); } static void *************** ATExecAlterColumnType(AlteredTableInfo * *** 7368,7376 **** add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid); /* ! * Drop any pg_statistic entry for the column, since it's now wrong type */ ! RemoveStatistics(RelationGetRelid(rel), attnum); /* * Update the default, if present, by brute force --- remove and re-add --- 7403,7411 ---- add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid); /* ! * Invalidate any pg_statistic entry for the column, since it's now wrong type */ ! InvalidateStatistics(RelationGetRelid(rel), attnum); /* * Update the default, if present, by brute force --- remove and re-add diff -dcrpN postgresql.orig/src/backend/executor/nodeHash.c postgresql.4/src/backend/executor/nodeHash.c *** postgresql.orig/src/backend/executor/nodeHash.c 2011-04-11 15:36:27.096816773 +0200 --- postgresql.4/src/backend/executor/nodeHash.c 2011-08-02 11:49:16.588371482 +0200 *************** *** 33,38 **** --- 33,39 ---- #include "executor/nodeHashjoin.h" #include "miscadmin.h" #include "parser/parse_expr.h" + #include "utils/builtins.h" #include "utils/dynahash.h" #include "utils/memutils.h" #include "utils/lsyscache.h" *************** ExecHashBuildSkewHash(HashJoinTable hash *** 1126,1131 **** --- 1127,1133 ---- int nvalues; float4 *numbers; int nnumbers; + int2vector *attnumvector; /* Do nothing if planner didn't identify the outer relation's join key */ if (!OidIsValid(node->skewTable)) *************** ExecHashBuildSkewHash(HashJoinTable hash *** 1137,1146 **** /* * Try to find the MCV statistics for the outer relation's join key. */ statsTuple = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(node->skewTable), ! Int16GetDatum(node->skewColumn), BoolGetDatum(node->skewInherit)); if (!HeapTupleIsValid(statsTuple)) return; --- 1139,1161 ---- /* * Try to find the MCV statistics for the outer relation's join key. */ + attnumvector = buildint2vector(&(node->skewColumn), 1); statsTuple = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(node->skewTable), ! PointerGetDatum(attnumvector), BoolGetDatum(node->skewInherit)); + pfree(attnumvector); + + /* check whether the stats entry is valid */ + if (HeapTupleIsValid(statsTuple)) + { + if (!((Form_pg_statistic)GETSTRUCT(statsTuple))->stavalid) + { + ReleaseSysCache(statsTuple); + statsTuple = NULL; + } + } + if (!HeapTupleIsValid(statsTuple)) return; diff -dcrpN postgresql.orig/src/backend/tsearch/ts_typanalyze.c postgresql.4/src/backend/tsearch/ts_typanalyze.c *** postgresql.orig/src/backend/tsearch/ts_typanalyze.c 2011-01-04 15:13:16.013557090 +0100 --- postgresql.4/src/backend/tsearch/ts_typanalyze.c 2011-08-02 11:49:16.626368688 +0200 *************** Datum *** 55,70 **** ts_typanalyze(PG_FUNCTION_ARGS) { VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0); - Form_pg_attribute attr = stats->attr; ! /* If the attstattarget column is negative, use the default value */ ! /* NB: it is okay to scribble on stats->attr since it's a copy */ ! if (attr->attstattarget < 0) ! attr->attstattarget = default_statistics_target; stats->compute_stats = compute_tsvector_stats; /* see comment about the choice of minrows in commands/analyze.c */ ! stats->minrows = 300 * attr->attstattarget; PG_RETURN_BOOL(true); } --- 55,69 ---- ts_typanalyze(PG_FUNCTION_ARGS) { VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0); ! /* If the statarget column is negative, use the default value */ ! /* NB: it is okay to scribble on stats->statarget since it's a copy */ ! if (stats->statarget < 0) ! stats->statarget = default_statistics_target; stats->compute_stats = compute_tsvector_stats; /* see comment about the choice of minrows in commands/analyze.c */ ! stats->minrows = 300 * stats->statarget; PG_RETURN_BOOL(true); } *************** compute_tsvector_stats(VacAttrStats *sta *** 167,173 **** * the number of individual lexeme values tracked in pg_statistic ought to * be more than the number of values for a simple scalar column. */ ! num_mcelem = stats->attr->attstattarget * 10; /* * We set bucket width equal to (num_mcelem + 10) / 0.007 as per the --- 166,172 ---- * the number of individual lexeme values tracked in pg_statistic ought to * be more than the number of values for a simple scalar column. */ ! num_mcelem = stats->statarget * 10; /* * We set bucket width equal to (num_mcelem + 10) / 0.007 as per the diff -dcrpN postgresql.orig/src/backend/utils/adt/int.c postgresql.4/src/backend/utils/adt/int.c *** postgresql.orig/src/backend/utils/adt/int.c 2011-06-20 10:11:35.739660477 +0200 --- postgresql.4/src/backend/utils/adt/int.c 2011-07-27 15:13:09.758534476 +0200 *************** int2vectorsend(PG_FUNCTION_ARGS) *** 254,274 **** return array_send(fcinfo); } - /* - * We don't have a complete set of int2vector support routines, - * but we need int2vectoreq for catcache indexing. - */ Datum int2vectoreq(PG_FUNCTION_ARGS) { ! int2vector *a = (int2vector *) PG_GETARG_POINTER(0); ! int2vector *b = (int2vector *) PG_GETARG_POINTER(1); ! if (a->dim1 != b->dim1) ! PG_RETURN_BOOL(false); ! PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * sizeof(int2)) == 0); } /***************************************************************************** * PUBLIC ROUTINES * --- 254,306 ---- return array_send(fcinfo); } Datum int2vectoreq(PG_FUNCTION_ARGS) { ! int32 cmp = DatumGetInt32(btint2vectorcmp(fcinfo)); ! PG_RETURN_BOOL(cmp == 0); ! } ! ! Datum ! int2vectorne(PG_FUNCTION_ARGS) ! { ! int32 cmp = DatumGetInt32(btint2vectorcmp(fcinfo)); ! ! PG_RETURN_BOOL(cmp != 0); ! } ! ! Datum ! int2vectorlt(PG_FUNCTION_ARGS) ! { ! int32 cmp = DatumGetInt32(btint2vectorcmp(fcinfo)); ! ! PG_RETURN_BOOL(cmp < 0); } + Datum + int2vectorle(PG_FUNCTION_ARGS) + { + int32 cmp = DatumGetInt32(btint2vectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp <= 0); + } + + Datum + int2vectorge(PG_FUNCTION_ARGS) + { + int32 cmp = DatumGetInt32(btint2vectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp >= 0); + } + + Datum + int2vectorgt(PG_FUNCTION_ARGS) + { + int32 cmp = DatumGetInt32(btint2vectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp > 0); + } /***************************************************************************** * PUBLIC ROUTINES * diff -dcrpN postgresql.orig/src/backend/utils/adt/selfuncs.c postgresql.4/src/backend/utils/adt/selfuncs.c *** postgresql.orig/src/backend/utils/adt/selfuncs.c 2011-07-18 15:42:00.064375706 +0200 --- postgresql.4/src/backend/utils/adt/selfuncs.c 2011-08-02 11:49:16.651366852 +0200 *************** get_join_variables(PlannerInfo *root, Li *** 4072,4077 **** --- 4072,4105 ---- } /* + * validate_statistics -- sets vardata->statsTuple only if the statistics is valid + */ + void + validate_statistics(VariableStatData *vardata, + Oid relid, AttrNumber *attnums, int n_attnums, bool inherited) + { + int2vector *attnumvector = buildint2vector(attnums, n_attnums); + HeapTuple tuple; + + tuple = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(relid), + PointerGetDatum(attnumvector), + BoolGetDatum(inherited)); + pfree(attnumvector); + + if (HeapTupleIsValid(tuple)) + { + if (((Form_pg_statistic) GETSTRUCT(tuple))->stavalid) + { + vardata->statsTuple = tuple; + vardata->freefunc = ReleaseSysCache; + } + else + ReleaseSysCache(tuple); + } + } + + /* * examine_variable * Try to look up statistical data about an expression. * Fill in a VariableStatData struct to describe the expression. *************** examine_variable(PlannerInfo *root, Node *** 4150,4160 **** } else if (rte->rtekind == RTE_RELATION) { ! vardata->statsTuple = SearchSysCache3(STATRELATTINH, ! ObjectIdGetDatum(rte->relid), ! Int16GetDatum(var->varattno), ! BoolGetDatum(rte->inh)); ! vardata->freefunc = ReleaseSysCache; } else { --- 4178,4184 ---- } else if (rte->rtekind == RTE_RELATION) { ! validate_statistics(vardata, rte->relid, &(var->varattno), 1, rte->inh); } else { *************** examine_variable(PlannerInfo *root, Node *** 4289,4300 **** } else if (index->indpred == NIL) { ! vardata->statsTuple = ! SearchSysCache3(STATRELATTINH, ! ObjectIdGetDatum(index->indexoid), ! Int16GetDatum(pos + 1), ! BoolGetDatum(false)); ! vardata->freefunc = ReleaseSysCache; } if (vardata->statsTuple) break; --- 4313,4321 ---- } else if (index->indpred == NIL) { ! int2 attnum = pos + 1; ! ! validate_statistics(vardata, index->indexoid, &attnum, 1, false); } if (vardata->statsTuple) break; *************** btcostestimate(PG_FUNCTION_ARGS) *** 6257,6269 **** elog(ERROR, "no function provided to release variable stats with"); } else ! { ! vardata.statsTuple = SearchSysCache3(STATRELATTINH, ! ObjectIdGetDatum(relid), ! Int16GetDatum(colnum), ! BoolGetDatum(rte->inh)); ! vardata.freefunc = ReleaseSysCache; ! } } else { --- 6278,6284 ---- elog(ERROR, "no function provided to release variable stats with"); } else ! validate_statistics(&vardata, relid, &colnum, 1, rte->inh); } else { *************** btcostestimate(PG_FUNCTION_ARGS) *** 6283,6295 **** elog(ERROR, "no function provided to release variable stats with"); } else ! { ! vardata.statsTuple = SearchSysCache3(STATRELATTINH, ! ObjectIdGetDatum(relid), ! Int16GetDatum(colnum), ! BoolGetDatum(false)); ! vardata.freefunc = ReleaseSysCache; ! } } if (HeapTupleIsValid(vardata.statsTuple)) --- 6298,6304 ---- elog(ERROR, "no function provided to release variable stats with"); } else ! validate_statistics(&vardata, relid, &colnum, 1, false); } if (HeapTupleIsValid(vardata.statsTuple)) diff -dcrpN postgresql.orig/src/backend/utils/cache/lsyscache.c postgresql.4/src/backend/utils/cache/lsyscache.c *** postgresql.orig/src/backend/utils/cache/lsyscache.c 2011-07-18 15:42:00.066375563 +0200 --- postgresql.4/src/backend/utils/cache/lsyscache.c 2011-08-02 11:49:16.684364424 +0200 *************** get_attavgwidth(Oid relid, AttrNumber at *** 2632,2637 **** --- 2632,2638 ---- { HeapTuple tp; int32 stawidth; + int2vector *attnumvector = NULL; if (get_attavgwidth_hook) { *************** get_attavgwidth(Oid relid, AttrNumber at *** 2639,2648 **** if (stawidth > 0) return stawidth; } tp = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(relid), ! Int16GetDatum(attnum), BoolGetDatum(false)); if (HeapTupleIsValid(tp)) { stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth; --- 2640,2651 ---- if (stawidth > 0) return stawidth; } + attnumvector = buildint2vector(&attnum, 1); tp = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(relid), ! PointerGetDatum(attnumvector), BoolGetDatum(false)); + pfree(attnumvector); if (HeapTupleIsValid(tp)) { stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth; *************** get_attstatsslot(HeapTuple statstuple, *** 2721,2728 **** val = SysCacheGetAttr(STATRELATTINH, statstuple, Anum_pg_statistic_stavalues1 + i, &isnull); if (isnull) ! elog(ERROR, "stavalues is null"); statarray = DatumGetArrayTypeP(val); /* --- 2724,2732 ---- val = SysCacheGetAttr(STATRELATTINH, statstuple, Anum_pg_statistic_stavalues1 + i, &isnull); + /* invalid stats record, i.e. analyze hasn't yet run for this column */ if (isnull) ! return false; statarray = DatumGetArrayTypeP(val); /* *************** get_attstatsslot(HeapTuple statstuple, *** 2775,2782 **** val = SysCacheGetAttr(STATRELATTINH, statstuple, Anum_pg_statistic_stanumbers1 + i, &isnull); if (isnull) ! elog(ERROR, "stanumbers is null"); statarray = DatumGetArrayTypeP(val); /* --- 2779,2787 ---- val = SysCacheGetAttr(STATRELATTINH, statstuple, Anum_pg_statistic_stanumbers1 + i, &isnull); + /* invalid stats record, i.e. analyze hasn't yet run for this column */ if (isnull) ! return false; statarray = DatumGetArrayTypeP(val); /* diff -dcrpN postgresql.orig/src/backend/utils/cache/syscache.c postgresql.4/src/backend/utils/cache/syscache.c *** postgresql.orig/src/backend/utils/cache/syscache.c 2011-06-20 10:11:35.741660316 +0200 --- postgresql.4/src/backend/utils/cache/syscache.c 2011-08-02 14:05:12.866629811 +0200 *************** static const struct cachedesc cacheinfo[ *** 588,598 **** 1024 }, {StatisticRelationId, /* STATRELATTINH */ ! StatisticRelidAttnumInhIndexId, 3, { Anum_pg_statistic_starelid, ! Anum_pg_statistic_staattnum, Anum_pg_statistic_stainherit, 0 }, --- 588,598 ---- 1024 }, {StatisticRelationId, /* STATRELATTINH */ ! StatisticRelidAttnumsInhIndexId, 3, { Anum_pg_statistic_starelid, ! Anum_pg_statistic_staattnums, Anum_pg_statistic_stainherit, 0 }, diff -dcrpN postgresql.orig/src/include/catalog/heap.h postgresql.4/src/include/catalog/heap.h *** postgresql.orig/src/include/catalog/heap.h 2011-07-24 18:16:45.286677978 +0200 --- postgresql.4/src/include/catalog/heap.h 2011-08-02 11:49:16.715362145 +0200 *************** extern void RemoveAttributeById(Oid reli *** 107,113 **** extern void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain); extern void RemoveAttrDefaultById(Oid attrdefId); ! extern void RemoveStatistics(Oid relid, AttrNumber attnum); extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids); --- 107,118 ---- extern void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain); extern void RemoveAttrDefaultById(Oid attrdefId); ! extern void AddStatistics(Oid relid, AttrNumber *attnums, ! int n_attnums, ! bool inherited, ! int statistics_target); ! extern void InvalidateStatistics(Oid relid, AttrNumber attnum); ! extern void RemoveStatistics(Oid relid, AttrNumber *attnums, int n_attnums); extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids); diff -dcrpN postgresql.orig/src/include/catalog/indexing.h postgresql.4/src/include/catalog/indexing.h *** postgresql.orig/src/include/catalog/indexing.h 2011-07-24 18:16:45.286677978 +0200 --- postgresql.4/src/include/catalog/indexing.h 2011-07-27 15:33:44.519543035 +0200 *************** DECLARE_INDEX(pg_shdepend_depender_index *** 218,225 **** DECLARE_INDEX(pg_shdepend_reference_index, 1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops)); #define SharedDependReferenceIndexId 1233 ! DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops)); ! #define StatisticRelidAttnumInhIndexId 2696 DECLARE_UNIQUE_INDEX(pg_tablespace_oid_index, 2697, on pg_tablespace using btree(oid oid_ops)); #define TablespaceOidIndexId 2697 --- 218,225 ---- DECLARE_INDEX(pg_shdepend_reference_index, 1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops)); #define SharedDependReferenceIndexId 1233 ! DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnums int2vector_ops, stainherit bool_ops)); ! #define StatisticRelidAttnumsInhIndexId 2696 DECLARE_UNIQUE_INDEX(pg_tablespace_oid_index, 2697, on pg_tablespace using btree(oid oid_ops)); #define TablespaceOidIndexId 2697 diff -dcrpN postgresql.orig/src/include/catalog/pg_amop.h postgresql.4/src/include/catalog/pg_amop.h *** postgresql.orig/src/include/catalog/pg_amop.h 2011-04-11 15:36:27.235807013 +0200 --- postgresql.4/src/include/catalog/pg_amop.h 2011-07-27 15:13:09.785532127 +0200 *************** DATA(insert ( 1991 30 30 4 s 648 403 0 *** 185,190 **** --- 185,200 ---- DATA(insert ( 1991 30 30 5 s 646 403 0 )); /* + * btree int2vector_ops + */ + + DATA(insert ( 3097 22 22 1 s 199 403 0 )); + DATA(insert ( 3097 22 22 2 s 322 403 0 )); + DATA(insert ( 3097 22 22 3 s 386 403 0 )); + DATA(insert ( 3097 22 22 4 s 323 403 0 )); + DATA(insert ( 3097 22 22 5 s 276 403 0 )); + + /* * btree float_ops */ diff -dcrpN postgresql.orig/src/include/catalog/pg_amproc.h postgresql.4/src/include/catalog/pg_amproc.h *** postgresql.orig/src/include/catalog/pg_amproc.h 2011-01-04 15:13:16.120551585 +0100 --- postgresql.4/src/include/catalog/pg_amproc.h 2011-07-27 15:13:09.793531431 +0200 *************** DATA(insert ( 2233 703 703 1 380 )); *** 123,128 **** --- 123,129 ---- DATA(insert ( 2234 704 704 1 381 )); DATA(insert ( 2789 27 27 1 2794 )); DATA(insert ( 2968 2950 2950 1 2960 )); + DATA(insert ( 3097 22 22 1 321 )); DATA(insert ( 3522 3500 3500 1 3514 )); diff -dcrpN postgresql.orig/src/include/catalog/pg_attribute.h postgresql.4/src/include/catalog/pg_attribute.h *** postgresql.orig/src/include/catalog/pg_attribute.h 2011-02-10 10:36:32.321680466 +0100 --- postgresql.4/src/include/catalog/pg_attribute.h 2011-08-02 11:59:09.569791405 +0200 *************** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP *** 48,62 **** Oid atttypid; /* - * attstattarget is the target number of statistics datapoints to collect - * during VACUUM ANALYZE of this column. A zero here indicates that we do - * not wish to collect any stats about this column. A "-1" here indicates - * that no value has been explicitly set for this column, so ANALYZE - * should use the default setting. - */ - int4 attstattarget; - - /* * attlen is a copy of the typlen field from pg_type for this attribute. * See atttypid comments above. */ --- 48,53 ---- *************** typedef FormData_pg_attribute *Form_pg_a *** 179,205 **** * ---------------- */ ! #define Natts_pg_attribute 20 #define Anum_pg_attribute_attrelid 1 #define Anum_pg_attribute_attname 2 #define Anum_pg_attribute_atttypid 3 ! #define Anum_pg_attribute_attstattarget 4 ! #define Anum_pg_attribute_attlen 5 ! #define Anum_pg_attribute_attnum 6 ! #define Anum_pg_attribute_attndims 7 ! #define Anum_pg_attribute_attcacheoff 8 ! #define Anum_pg_attribute_atttypmod 9 ! #define Anum_pg_attribute_attbyval 10 ! #define Anum_pg_attribute_attstorage 11 ! #define Anum_pg_attribute_attalign 12 ! #define Anum_pg_attribute_attnotnull 13 ! #define Anum_pg_attribute_atthasdef 14 ! #define Anum_pg_attribute_attisdropped 15 ! #define Anum_pg_attribute_attislocal 16 ! #define Anum_pg_attribute_attinhcount 17 ! #define Anum_pg_attribute_attcollation 18 ! #define Anum_pg_attribute_attacl 19 ! #define Anum_pg_attribute_attoptions 20 /* ---------------- --- 170,195 ---- * ---------------- */ ! #define Natts_pg_attribute 19 #define Anum_pg_attribute_attrelid 1 #define Anum_pg_attribute_attname 2 #define Anum_pg_attribute_atttypid 3 ! #define Anum_pg_attribute_attlen 4 ! #define Anum_pg_attribute_attnum 5 ! #define Anum_pg_attribute_attndims 6 ! #define Anum_pg_attribute_attcacheoff 7 ! #define Anum_pg_attribute_atttypmod 8 ! #define Anum_pg_attribute_attbyval 9 ! #define Anum_pg_attribute_attstorage 10 ! #define Anum_pg_attribute_attalign 11 ! #define Anum_pg_attribute_attnotnull 12 ! #define Anum_pg_attribute_atthasdef 13 ! #define Anum_pg_attribute_attisdropped 14 ! #define Anum_pg_attribute_attislocal 15 ! #define Anum_pg_attribute_attinhcount 16 ! #define Anum_pg_attribute_attcollation 17 ! #define Anum_pg_attribute_attacl 18 ! #define Anum_pg_attribute_attoptions 19 /* ---------------- diff -dcrpN postgresql.orig/src/include/catalog/pg_class.h postgresql.4/src/include/catalog/pg_class.h *** postgresql.orig/src/include/catalog/pg_class.h 2011-06-24 11:38:23.338906107 +0200 --- postgresql.4/src/include/catalog/pg_class.h 2011-08-02 14:03:43.862124993 +0200 *************** typedef FormData_pg_class *Form_pg_class *** 132,138 **** /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ )); DESCR(""); ! DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 20 0 f f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ )); DESCR(""); --- 132,138 ---- /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ )); DESCR(""); ! DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 19 0 f f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ )); DESCR(""); diff -dcrpN postgresql.orig/src/include/catalog/pg_opclass.h postgresql.4/src/include/catalog/pg_opclass.h *** postgresql.orig/src/include/catalog/pg_opclass.h 2011-01-04 15:13:16.125551330 +0100 --- postgresql.4/src/include/catalog/pg_opclass.h 2011-07-27 15:13:09.811529864 +0200 *************** DATA(insert ( 403 bpchar_pattern_ops PG *** 158,163 **** --- 158,164 ---- DATA(insert ( 403 money_ops PGNSP PGUID 2099 790 t 0 )); DATA(insert ( 405 bool_ops PGNSP PGUID 2222 16 t 0 )); DATA(insert ( 405 bytea_ops PGNSP PGUID 2223 17 t 0 )); + DATA(insert ( 403 int2vector_ops PGNSP PGUID 3097 22 t 0 )); DATA(insert ( 405 int2vector_ops PGNSP PGUID 2224 22 t 0 )); DATA(insert ( 403 tid_ops PGNSP PGUID 2789 27 t 0 )); DATA(insert ( 405 xid_ops PGNSP PGUID 2225 28 t 0 )); diff -dcrpN postgresql.orig/src/include/catalog/pg_operator.h postgresql.4/src/include/catalog/pg_operator.h *** postgresql.orig/src/include/catalog/pg_operator.h 2011-06-06 09:12:54.421675553 +0200 --- postgresql.4/src/include/catalog/pg_operator.h 2011-07-27 15:13:09.822528906 +0200 *************** DATA(insert OID = 98 ( "=" PGNSP PG *** 134,139 **** --- 134,150 ---- DESCR("equal"); #define TextEqualOperator 98 + DATA(insert OID = 114 ( "<>" PGNSP PGUID b f f 22 22 16 114 386 int2vectorne neqsel neqjoinsel )); + DESCR("not equal"); + DATA(insert OID = 199 ( "<" PGNSP PGUID b f f 22 22 16 276 323 int2vectorlt scalarltsel scalarltjoinsel )); + DESCR("less than"); + DATA(insert OID = 276 ( ">" PGNSP PGUID b f f 22 22 16 199 322 int2vectorgt scalargtsel scalargtjoinsel )); + DESCR("greater than"); + DATA(insert OID = 322 ( "<=" PGNSP PGUID b f f 22 22 16 323 276 int2vectorle scalarltsel scalarltjoinsel )); + DESCR("less than or equal"); + DATA(insert OID = 323 ( ">=" PGNSP PGUID b f f 22 22 16 322 199 int2vectorge scalargtsel scalargtjoinsel )); + DESCR("greater than or equal"); + DATA(insert OID = 349 ( "||" PGNSP PGUID b f f 2277 2283 2277 0 0 array_append - - )); DESCR("append element onto end of array"); DATA(insert OID = 374 ( "||" PGNSP PGUID b f f 2283 2277 2277 0 0 array_prepend - - )); *************** DATA(insert OID = 389 ( "!!" PGNSP P *** 151,157 **** DESCR("deprecated, use ! instead"); DATA(insert OID = 385 ( "=" PGNSP PGUID b f t 29 29 16 385 0 cideq eqsel eqjoinsel )); DESCR("equal"); ! DATA(insert OID = 386 ( "=" PGNSP PGUID b f t 22 22 16 386 0 int2vectoreq eqsel eqjoinsel )); DESCR("equal"); DATA(insert OID = 387 ( "=" PGNSP PGUID b t f 27 27 16 387 402 tideq eqsel eqjoinsel )); --- 162,168 ---- DESCR("deprecated, use ! instead"); DATA(insert OID = 385 ( "=" PGNSP PGUID b f t 29 29 16 385 0 cideq eqsel eqjoinsel )); DESCR("equal"); ! DATA(insert OID = 386 ( "=" PGNSP PGUID b t t 22 22 16 386 114 int2vectoreq eqsel eqjoinsel )); DESCR("equal"); DATA(insert OID = 387 ( "=" PGNSP PGUID b t f 27 27 16 387 402 tideq eqsel eqjoinsel )); diff -dcrpN postgresql.orig/src/include/catalog/pg_opfamily.h postgresql.4/src/include/catalog/pg_opfamily.h *** postgresql.orig/src/include/catalog/pg_opfamily.h 2011-01-04 15:13:16.126551278 +0100 --- postgresql.4/src/include/catalog/pg_opfamily.h 2011-07-27 15:13:09.836527688 +0200 *************** DATA(insert OID = 2099 ( 403 money_ops *** 114,119 **** --- 114,120 ---- DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID )); #define BOOL_HASH_FAM_OID 2222 DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID )); + DATA(insert OID = 3097 ( 403 int2vector_ops PGNSP PGUID )); DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID )); DATA(insert OID = 2789 ( 403 tid_ops PGNSP PGUID )); DATA(insert OID = 2225 ( 405 xid_ops PGNSP PGUID )); diff -dcrpN postgresql.orig/src/include/catalog/pg_proc.h postgresql.4/src/include/catalog/pg_proc.h *** postgresql.orig/src/include/catalog/pg_proc.h 2011-07-18 15:42:00.078374691 +0200 --- postgresql.4/src/include/catalog/pg_proc.h 2011-07-27 15:27:18.053344124 +0200 *************** DESCR("length"); *** 216,221 **** --- 216,228 ---- DATA(insert OID = 1258 ( textcat PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 25 "25 25" _null_ _null_ _null_ _null_ textcat _null_ _null_ _null_ )); DATA(insert OID = 84 ( boolne PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "16 16" _null_ _null_ _null_ _null_ boolne _null_ _null_ _null_ )); + + DATA(insert OID = 86 ( int2vectorne PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "22 22" _null_ _null_ _null_ _null_ int2vectorne _null_ _null_ _null_ )); + DATA(insert OID = 87 ( int2vectorlt PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "22 22" _null_ _null_ _null_ _null_ int2vectorlt _null_ _null_ _null_ )); + DATA(insert OID = 88 ( int2vectorle PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "22 22" _null_ _null_ _null_ _null_ int2vectorle _null_ _null_ _null_ )); + DATA(insert OID = 90 ( int2vectorge PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "22 22" _null_ _null_ _null_ _null_ int2vectorge _null_ _null_ _null_ )); + DATA(insert OID = 3122 ( int2vectorgt PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "22 22" _null_ _null_ _null_ _null_ int2vectorgt _null_ _null_ _null_ )); + DATA(insert OID = 89 ( version PGNSP PGUID 12 1 0 0 0 f f f t f s 0 0 25 "" _null_ _null_ _null_ _null_ pgsql_version _null_ _null_ _null_ )); DESCR("PostgreSQL version string"); *************** DESCR("I/O"); *** 566,571 **** --- 573,580 ---- DATA(insert OID = 350 ( btint2cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "21 21" _null_ _null_ _null_ _null_ btint2cmp _null_ _null_ _null_ )); DESCR("less-equal-greater"); + DATA(insert OID = 321 ( btint2vectorcmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "22 22" _null_ _null_ _null_ _null_ btint2vectorcmp _null_ _null_ _null_ )); + DESCR("less-equal-greater"); DATA(insert OID = 351 ( btint4cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "23 23" _null_ _null_ _null_ _null_ btint4cmp _null_ _null_ _null_ )); DESCR("less-equal-greater"); DATA(insert OID = 842 ( btint8cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "20 20" _null_ _null_ _null_ _null_ btint8cmp _null_ _null_ _null_ )); diff -dcrpN postgresql.orig/src/include/catalog/pg_statistic.h postgresql.4/src/include/catalog/pg_statistic.h *** postgresql.orig/src/include/catalog/pg_statistic.h 2011-02-22 18:51:42.762512469 +0100 --- postgresql.4/src/include/catalog/pg_statistic.h 2011-08-02 11:49:16.758358984 +0200 *************** *** 40,50 **** CATALOG(pg_statistic,2619) BKI_WITHOUT_OIDS { ! /* These fields form the unique key for the entry: */ Oid starelid; /* relation containing attribute */ - int2 staattnum; /* attribute (column) stats are for */ bool stainherit; /* true if inheritance children are included */ /* the fraction of the column's entries that are NULL: */ float4 stanullfrac; --- 40,63 ---- CATALOG(pg_statistic,2619) BKI_WITHOUT_OIDS { ! /* ! * These fields (together with the staattnums field below in the variable fields) ! * form the unique key for the entry: ! */ Oid starelid; /* relation containing attribute */ bool stainherit; /* true if inheritance children are included */ + /* this entry is valid */ + bool stavalid; + + /* statarget is the target number of statistics datapoints to collect + * during VACUUM ANALYZE of this column. A zero here indicates that we do + * not wish to collect any stats about this column. A "-1" here indicates + * that no value has been explicitly set for this column, so ANALYZE + * should use the default setting. + */ + int4 statarget; + /* the fraction of the column's entries that are NULL: */ float4 stanullfrac; *************** CATALOG(pg_statistic,2619) BKI_WITHOUT_O *** 110,115 **** --- 123,129 ---- * the full field access machinery (heap_getattr) for them. We declare * them here for the catalog machinery. */ + int2vector staattnums; /* attributes (columns) stats are for */ float4 stanumbers1[1]; float4 stanumbers2[1]; *************** typedef FormData_pg_statistic *Form_pg_s *** 143,171 **** * compiler constants for pg_statistic * ---------------- */ ! #define Natts_pg_statistic 22 #define Anum_pg_statistic_starelid 1 ! #define Anum_pg_statistic_staattnum 2 ! #define Anum_pg_statistic_stainherit 3 ! #define Anum_pg_statistic_stanullfrac 4 ! #define Anum_pg_statistic_stawidth 5 ! #define Anum_pg_statistic_stadistinct 6 ! #define Anum_pg_statistic_stakind1 7 ! #define Anum_pg_statistic_stakind2 8 ! #define Anum_pg_statistic_stakind3 9 ! #define Anum_pg_statistic_stakind4 10 ! #define Anum_pg_statistic_staop1 11 ! #define Anum_pg_statistic_staop2 12 ! #define Anum_pg_statistic_staop3 13 ! #define Anum_pg_statistic_staop4 14 ! #define Anum_pg_statistic_stanumbers1 15 ! #define Anum_pg_statistic_stanumbers2 16 ! #define Anum_pg_statistic_stanumbers3 17 ! #define Anum_pg_statistic_stanumbers4 18 ! #define Anum_pg_statistic_stavalues1 19 ! #define Anum_pg_statistic_stavalues2 20 ! #define Anum_pg_statistic_stavalues3 21 ! #define Anum_pg_statistic_stavalues4 22 /* * Currently, three statistical slot "kinds" are defined: most common values, --- 157,187 ---- * compiler constants for pg_statistic * ---------------- */ ! #define Natts_pg_statistic 24 #define Anum_pg_statistic_starelid 1 ! #define Anum_pg_statistic_stainherit 2 ! #define Anum_pg_statistic_stavalid 3 ! #define Anum_pg_statistic_statarget 4 ! #define Anum_pg_statistic_stanullfrac 5 ! #define Anum_pg_statistic_stawidth 6 ! #define Anum_pg_statistic_stadistinct 7 ! #define Anum_pg_statistic_stakind1 8 ! #define Anum_pg_statistic_stakind2 9 ! #define Anum_pg_statistic_stakind3 10 ! #define Anum_pg_statistic_stakind4 11 ! #define Anum_pg_statistic_staop1 12 ! #define Anum_pg_statistic_staop2 13 ! #define Anum_pg_statistic_staop3 14 ! #define Anum_pg_statistic_staop4 15 ! #define Anum_pg_statistic_staattnums 16 ! #define Anum_pg_statistic_stanumbers1 17 ! #define Anum_pg_statistic_stanumbers2 18 ! #define Anum_pg_statistic_stanumbers3 19 ! #define Anum_pg_statistic_stanumbers4 20 ! #define Anum_pg_statistic_stavalues1 21 ! #define Anum_pg_statistic_stavalues2 22 ! #define Anum_pg_statistic_stavalues3 23 ! #define Anum_pg_statistic_stavalues4 24 /* * Currently, three statistical slot "kinds" are defined: most common values, diff -dcrpN postgresql.orig/src/include/commands/vacuum.h postgresql.4/src/include/commands/vacuum.h *** postgresql.orig/src/include/commands/vacuum.h 2011-06-02 10:21:24.006634564 +0200 --- postgresql.4/src/include/commands/vacuum.h 2011-08-02 11:49:16.768358249 +0200 *************** typedef struct VacAttrStats *** 74,79 **** --- 74,83 ---- * information about the datatype being fed to the typanalyze function. */ Form_pg_attribute attr; /* copy of pg_attribute row for column */ + int4 statarget; /* effective statistics target */ + int4 oldtarget; /* statistics target in pg_statistic + this must be kept so the -1 to denote + default_statistics_target is not overwritten */ Oid attrtypid; /* type of data being analyzed */ int32 attrtypmod; /* typmod of data being analyzed */ Form_pg_type attrtype; /* copy of pg_type row for attrtypid */ diff -dcrpN postgresql.orig/src/include/utils/builtins.h postgresql.4/src/include/utils/builtins.h *** postgresql.orig/src/include/utils/builtins.h 2011-06-24 11:38:23.342905815 +0200 --- postgresql.4/src/include/utils/builtins.h 2011-07-27 15:13:09.893522727 +0200 *************** extern Datum int2vectorout(PG_FUNCTION_A *** 174,179 **** --- 174,184 ---- extern Datum int2vectorrecv(PG_FUNCTION_ARGS); extern Datum int2vectorsend(PG_FUNCTION_ARGS); extern Datum int2vectoreq(PG_FUNCTION_ARGS); + extern Datum int2vectorne(PG_FUNCTION_ARGS); + extern Datum int2vectorlt(PG_FUNCTION_ARGS); + extern Datum int2vectorle(PG_FUNCTION_ARGS); + extern Datum int2vectorgt(PG_FUNCTION_ARGS); + extern Datum int2vectorge(PG_FUNCTION_ARGS); extern Datum int4in(PG_FUNCTION_ARGS); extern Datum int4out(PG_FUNCTION_ARGS); extern Datum int4recv(PG_FUNCTION_ARGS); *************** extern void pg_lltoa(int64 ll, char *a); *** 283,288 **** --- 288,294 ---- */ extern Datum btboolcmp(PG_FUNCTION_ARGS); extern Datum btint2cmp(PG_FUNCTION_ARGS); + extern Datum btint2vectorcmp(PG_FUNCTION_ARGS); extern Datum btint4cmp(PG_FUNCTION_ARGS); extern Datum btint8cmp(PG_FUNCTION_ARGS); extern Datum btfloat4cmp(PG_FUNCTION_ARGS); diff -dcrpN postgresql.orig/src/include/utils/selfuncs.h postgresql.4/src/include/utils/selfuncs.h *** postgresql.orig/src/include/utils/selfuncs.h 2011-06-10 11:06:01.495860021 +0200 --- postgresql.4/src/include/utils/selfuncs.h 2011-08-02 11:49:16.788356778 +0200 *************** typedef bool (*get_index_stats_hook_type *** 110,115 **** --- 110,119 ---- VariableStatData *vardata); extern PGDLLIMPORT get_index_stats_hook_type get_index_stats_hook; + extern void validate_statistics(VariableStatData *vardata, + Oid relid, + AttrNumber *attnums, int n_attnums, + bool inherited); extern void examine_variable(PlannerInfo *root, Node *node, int varRelid, VariableStatData *vardata); extern bool get_restriction_variable(PlannerInfo *root, List *args, diff -dcrpN postgresql.orig/src/test/regress/expected/rules.out postgresql.4/src/test/regress/expected/rules.out *** postgresql.orig/src/test/regress/expected/rules.out 2011-07-24 18:16:45.313676620 +0200 --- postgresql.4/src/test/regress/expected/rules.out 2011-07-27 15:33:44.546540690 +0200 *************** SELECT viewname, definition FROM pg_view *** 1317,1323 **** pg_statio_user_indexes | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE ((pg_statio_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_indexes.schemaname !~ '^pg_toast'::text)); pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE ((pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_sequences.schemaname !~ '^pg_toast'::text)); pg_statio_user_tables | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE ((pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_tables.schemaname !~ '^pg_toast'::text)); ! pg_stats | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stainherit AS inherited, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text)); pg_tables | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS tablespace, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, c.relhastriggers AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char"); pg_timezone_abbrevs | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst); pg_timezone_names | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst); --- 1317,1323 ---- pg_statio_user_indexes | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE ((pg_statio_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_indexes.schemaname !~ '^pg_toast'::text)); pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE ((pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_sequences.schemaname !~ '^pg_toast'::text)); pg_statio_user_tables | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE ((pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_tables.schemaname !~ '^pg_toast'::text)); ! pg_stats | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stainherit AS inherited, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON ((((c.oid = a.attrelid) AND (array_length(s.staattnums, 1) = 1)) AND (a.attnum = s.staattnums[0])))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text)); pg_tables | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS tablespace, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, c.relhastriggers AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char"); pg_timezone_abbrevs | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst); pg_timezone_names | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst);