ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Started by Robert Haasalmost 17 years ago46 messages
#1Robert Haas
robertmhaas@gmail.com
1 attachment(s)

Per previous discussion.

http://archives.postgresql.org/message-id/8066.1229106059@sss.pgh.pa.us
http://archives.postgresql.org/message-id/603c8f070904021926g92eb55sdfc68141133957c1@mail.gmail.com

I decided on SET DISTINCT rather than SET NDISTINCT for the DDL
command because DISTINCT is already a keyword, and there didn't seem
to be any compelling reason to invent a new one.

...Robert

Attachments:

ndistinct-1.patchtext/x-patch; charset=US-ASCII; name=ndistinct-1.patchDownload
*** a/doc/src/sgml/ref/alter_table.sgml
--- b/doc/src/sgml/ref/alter_table.sgml
***************
*** 39,44 **** where <replaceable class="PARAMETER">action</replaceable> is one of:
--- 39,45 ----
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
+     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DISTINCT<replaceable class="PARAMETER">integer</replaceable>
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
      ADD <replaceable class="PARAMETER">table_constraint</replaceable>
      DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
***************
*** 154,159 **** where <replaceable class="PARAMETER">action</replaceable> is one of:
--- 155,185 ----
     </varlistentry>
  
     <varlistentry>
+     <term><literal>SET DISTINCT</literal></term>
+     <listitem>
+      <para>
+       This form can be used to override the result of the ndistinct computation
+       performed by subsequent
+       <xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
+       When set to a positive value, ANALYZE will assume that the column
+       contains exactly the specified number of distinct values (even if its
+       own analysis indicates otherwie).  When set to a negative value, which
+       must be greater than or equal to -1000000, it will assume that the
+       number of distinct values in the column linear in the size of the table,
+       with a coefficient of -0.000001 times the specified value.  This can
+       be useful when the size of the table changes over time; the
+       multiplication by the number of rows in the table is not performed until
+       query planning time.
+       Use a value of 0 to revert to computing the number of distinct values
+       normally.
+       For more information on the use of statistics by the
+       <productname>PostgreSQL</productname> query planner, refer to
+       <xref linkend="planner-stats">.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <indexterm>
       <primary>TOAST</primary>
       <secondary>per-column storage settings</secondary>
*** a/doc/src/sgml/ref/analyze.sgml
--- b/doc/src/sgml/ref/analyze.sgml
***************
*** 160,165 **** ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> [ ( <re
--- 160,175 ----
    </para>
  
    <para>
+    The analyzer also estimates the number of distinct values that appear
+    in each column.  Because only a subset of pages are scanned, this method
+    can sometimes be quite inaccurate, especially for large tables.  If this
+    inaccuracy leads to bad query plans, the analyzer can be forced to use
+    a more correct value with <command>ALTER TABLE ... ALTER COLUMN ... SET
+    STATISTICS</command> (see <xref linkend="sql-altertable"
+    endterm="sql-altertable-title">).
+   </para>
+ 
+   <para>
     The largest statistics target among the columns being analyzed determines
     the number of table rows sampled to prepare the statistics.  Increasing
     the target causes a proportional increase in the time and space needed
*** a/src/backend/access/common/tupdesc.c
--- b/src/backend/access/common/tupdesc.c
***************
*** 338,343 **** equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
--- 338,345 ----
  			return false;
  		if (attr1->attstattarget != attr2->attstattarget)
  			return false;
+ 		if (attr1->attdistinct != attr2->attdistinct)
+ 			return false;
  		if (attr1->attlen != attr2->attlen)
  			return false;
  		if (attr1->attndims != attr2->attndims)
***************
*** 465,470 **** TupleDescInitEntry(TupleDesc desc,
--- 467,473 ----
  		MemSet(NameStr(att->attname), 0, NAMEDATALEN);
  
  	att->attstattarget = -1;
+ 	att->attdistinct = 0;
  	att->attcacheoff = -1;
  	att->atttypmod = typmod;
  
*** a/src/backend/bootstrap/bootstrap.c
--- b/src/backend/bootstrap/bootstrap.c
***************
*** 743,748 **** DefineAttr(char *name, char *type, int attnum)
--- 743,749 ----
  	}
  
  	attrtypes[attnum]->attstattarget = -1;
+ 	attrtypes[attnum]->attdistinct = 0;
  	attrtypes[attnum]->attcacheoff = -1;
  	attrtypes[attnum]->atttypmod = -1;
  	attrtypes[attnum]->attislocal = true;
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 111,147 **** static List *insert_ordered_unique_oid(List *list, Oid datum);
   */
  
  static FormData_pg_attribute a1 = {
! 	0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
  	SelfItemPointerAttributeNumber, 0, -1, -1,
  	false, 'p', 's', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a2 = {
! 	0, {"oid"}, OIDOID, 0, sizeof(Oid),
  	ObjectIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a3 = {
! 	0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
  	MinTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a4 = {
! 	0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
  	MinCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a5 = {
! 	0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
  	MaxTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a6 = {
! 	0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
  	MaxCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
--- 111,147 ----
   */
  
  static FormData_pg_attribute a1 = {
! 	0, {"ctid"}, TIDOID, 0, 0, sizeof(ItemPointerData),
  	SelfItemPointerAttributeNumber, 0, -1, -1,
  	false, 'p', 's', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a2 = {
! 	0, {"oid"}, OIDOID, 0, 0, sizeof(Oid),
  	ObjectIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a3 = {
! 	0, {"xmin"}, XIDOID, 0, 0, sizeof(TransactionId),
  	MinTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a4 = {
! 	0, {"cmin"}, CIDOID, 0, 0, sizeof(CommandId),
  	MinCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a5 = {
! 	0, {"xmax"}, XIDOID, 0, 0, sizeof(TransactionId),
  	MaxTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a6 = {
! 	0, {"cmax"}, CIDOID, 0, 0, sizeof(CommandId),
  	MaxCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
***************
*** 153,159 **** static FormData_pg_attribute a6 = {
   * 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, { 0 }
  };
--- 153,159 ----
   * used in SQL.
   */
  static FormData_pg_attribute a7 = {
! 	0, {"tableoid"}, OIDOID, 0, 0, sizeof(Oid),
  	TableOidAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
***************
*** 514,519 **** InsertPgAttributeTuple(Relation pg_attribute_rel,
--- 514,520 ----
  	values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
  	values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
  	values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
+ 	values[Anum_pg_attribute_attdistinct - 1] = Float8GetDatum(new_attribute->attdistinct);
  
  	/* start out with empty permissions */
  	nulls[Anum_pg_attribute_attacl - 1] = true;
***************
*** 570,575 **** AddNewAttributeTuples(Oid new_rel_oid,
--- 571,577 ----
  		attr->attrelid = new_rel_oid;
  		/* Make sure these are OK, too */
  		attr->attstattarget = -1;
+ 		attr->attdistinct = 0;
  		attr->attcacheoff = -1;
  
  		InsertPgAttributeTuple(rel, attr, indstate);
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 187,192 **** ConstructTupleDescriptor(Relation heapRelation,
--- 187,193 ----
  			to->attnum = i + 1;
  
  			to->attstattarget = -1;
+ 			to->attdistinct = 0;
  			to->attcacheoff = -1;
  			to->attnotnull = false;
  			to->atthasdef = false;
*** a/src/backend/commands/analyze.c
--- b/src/backend/commands/analyze.c
***************
*** 434,439 **** analyze_rel(Oid relid, VacuumStmt *vacstmt,
--- 434,454 ----
  									 std_fetch_func,
  									 numrows,
  									 totalrows);
+ 
+ 			/*
+ 		 	 * If the user has overridden the result of our stadistinct
+ 		 	 * calculation using ALTER TABLE ... ALTER COLUMN ... SET DISTINCT,
+ 		 	 * fill in the override value now.  attdistinct is an integer, so
+ 		 	 * negative values are stored multiplied by one million.
+ 		 	 */
+ 			if (stats->attr->attdistinct != 0)
+ 			{
+ 				if (stats->attr->attdistinct > 0)
+ 					stats->stadistinct = stats->attr->attdistinct;
+ 				else
+ 					stats->stadistinct = stats->attr->attdistinct * 0.000001;
+ 			}
+ 
  			MemoryContextResetAndDeleteChildren(col_context);
  		}
  
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 283,288 **** static void ATPrepSetStatistics(Relation rel, const char *colName,
--- 283,290 ----
  					Node *flagValue);
  static void ATExecSetStatistics(Relation rel, const char *colName,
  					Node *newValue);
+ static void ATExecSetDistinct(Relation rel, const char *colName,
+ 				 Node *newValue);
  static void ATExecSetStorage(Relation rel, const char *colName,
  				 Node *newValue);
  static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
***************
*** 2401,2406 **** ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
--- 2403,2414 ----
  			ATPrepSetStatistics(rel, cmd->name, cmd->def);
  			pass = AT_PASS_COL_ATTRS;
  			break;
+ 		case AT_SetDistinct:	/* ALTER COLUMN STATISTICS */
+ 			ATSimplePermissions(rel, false);
+ 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
+ 			/* No command-specific prep needed */
+ 			pass = AT_PASS_COL_ATTRS;
+ 			break;
  		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATSimplePermissions(rel, false);
  			ATSimpleRecursion(wqueue, rel, cmd, recurse);
***************
*** 2610,2619 **** ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
  		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATExecSetNotNull(tab, rel, cmd->name);
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN STATISTICS */
  			ATExecSetStatistics(rel, cmd->name, cmd->def);
  			break;
! 		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATExecSetStorage(rel, cmd->name, cmd->def);
  			break;
  		case AT_DropColumn:		/* DROP COLUMN */
--- 2618,2630 ----
  		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATExecSetNotNull(tab, rel, cmd->name);
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
  			ATExecSetStatistics(rel, cmd->name, cmd->def);
  			break;
! 		case AT_SetDistinct:	/* ALTER COLUMN SET DISTINCT */
! 			ATExecSetDistinct(rel, cmd->name, cmd->def);
! 			break;
! 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
  			ATExecSetStorage(rel, cmd->name, cmd->def);
  			break;
  		case AT_DropColumn:		/* DROP COLUMN */
***************
*** 4075,4080 **** ATExecSetStatistics(Relation rel, const char *colName, Node *newValue)
--- 4086,4145 ----
  }
  
  /*
+  * ALTER TABLE ALTER COLUMN SET DISTINCT
+  */
+ static void
+ ATExecSetDistinct(Relation rel, const char *colName, Node *newValue)
+ {
+ 	int			newdistinct;
+ 	Relation	attrelation;
+ 	HeapTuple	tuple;
+ 	Form_pg_attribute attrtuple;
+ 
+ 	Assert(IsA(newValue, Integer));
+ 	newdistinct = intVal(newValue);
+ 
+ 	/*
+ 	 * Limit target to a sane range
+ 	 */
+ 	if (newdistinct < -1000000)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				 errmsg("number of distinct values %d is too low",
+ 						newdistinct)));
+ 	}
+ 
+ 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
+ 
+ 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_COLUMN),
+ 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
+ 						colName, RelationGetRelationName(rel))));
+ 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
+ 
+ 	if (attrtuple->attnum <= 0)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot alter system column \"%s\"",
+ 						colName)));
+ 
+ 	attrtuple->attdistinct = newdistinct;
+ 
+ 	simple_heap_update(attrelation, &tuple->t_self, tuple);
+ 
+ 	/* keep system catalog indexes current */
+ 	CatalogUpdateIndexes(attrelation, tuple);
+ 
+ 	heap_freetuple(tuple);
+ 
+ 	heap_close(attrelation, RowExclusiveLock);
+ }
+ 
+ /*
   * ALTER TABLE ALTER COLUMN SET STORAGE
   */
  static void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 1588,1593 **** alter_table_cmd:
--- 1588,1602 ----
  					n->def = (Node *) makeInteger($6);
  					$$ = (Node *)n;
  				}
+ 			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET DISTINCT <SignedIconst> */
+ 			| ALTER opt_column ColId SET DISTINCT SignedIconst
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_SetDistinct;
+ 					n->name = $3;
+ 					n->def = (Node *) makeInteger($6);
+ 					$$ = (Node *)n;
+ 				}
  			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
  			| ALTER opt_column ColId SET STORAGE ColId
  				{
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 4639,4644 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4639,4645 ----
  	int			i_atttypname;
  	int			i_atttypmod;
  	int			i_attstattarget;
+ 	int			i_attdistinct;
  	int			i_attstorage;
  	int			i_typstorage;
  	int			i_attnotnull;
***************
*** 4684,4690 **** getTableAttrs(TableInfo *tblinfo, int numTables)
  
  		resetPQExpBuffer(q);
  
! 		if (g_fout->remoteVersion >= 70300)
  		{
  			/* need left join here to not fail on dropped columns ... */
  			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
--- 4685,4707 ----
  
  		resetPQExpBuffer(q);
  
! 		if (g_fout->remoteVersion >= 80400)
! 		{
! 			/* attdistinct doesn't exist prior to 8.4 */
! 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
! 								 "a.attstattarget, a.attdistinct, "
! 								 "a.attstorage, t.typstorage, a.attnotnull, "
! 								 "a.atthasdef, a.attisdropped, a.attlen, "
! 								 "a.attalign, a.attislocal, "
! 				   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
! 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
! 							  "ON a.atttypid = t.oid "
! 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
! 							  "AND a.attnum > 0::pg_catalog.int2 "
! 							  "ORDER BY a.attrelid, a.attnum",
! 							  tbinfo->dobj.catId.oid);
! 		}
! 		else if (g_fout->remoteVersion >= 70300)
  		{
  			/* need left join here to not fail on dropped columns ... */
  			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
***************
*** 4746,4751 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4763,4769 ----
  		i_atttypname = PQfnumber(res, "atttypname");
  		i_atttypmod = PQfnumber(res, "atttypmod");
  		i_attstattarget = PQfnumber(res, "attstattarget");
+ 		i_attdistinct = PQfnumber(res, "attdistinct");
  		i_attstorage = PQfnumber(res, "attstorage");
  		i_typstorage = PQfnumber(res, "typstorage");
  		i_attnotnull = PQfnumber(res, "attnotnull");
***************
*** 4760,4765 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4778,4784 ----
  		tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
  		tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
  		tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
+ 		tbinfo->attdistinct = (int *) malloc(ntups * sizeof(int));
  		tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
  		tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
  		tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
***************
*** 4785,4790 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4804,4810 ----
  			tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
  			tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
  			tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
+ 			tbinfo->attdistinct[j] = atoi(PQgetvalue(res, j, i_attdistinct));
  			tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
  			tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
  			tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
***************
*** 9934,9939 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
--- 9954,9975 ----
  			}
  
  			/*
+ 			 * Dump per-column distinct information. We only issue an ALTER
+ 			 * TABLE statement if the attdistinct entry for this column is
+ 			 * non-zero (i.e. it's not the default value)
+ 			 */
+ 			if (tbinfo->attdistinct[j] != 0 &&
+ 				!tbinfo->attisdropped[j])
+ 			{
+ 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
+ 								  fmtId(tbinfo->dobj.name));
+ 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
+ 								  fmtId(tbinfo->attnames[j]));
+ 				appendPQExpBuffer(q, "SET DISTINCT %d;\n",
+ 								  tbinfo->attdistinct[j]);
+ 			}
+ 
+ 			/*
  			 * Dump per-column storage information.  The statement is only
  			 * dumped if the storage has been changed from the type's default.
  			 */
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
***************
*** 243,248 **** typedef struct _tableInfo
--- 243,249 ----
  	char	  **atttypnames;	/* attribute type names */
  	int		   *atttypmod;		/* type-specific type modifiers */
  	int		   *attstattarget;	/* attribute statistics targets */
+ 	int		   *attdistinct;	/* override ndistinct calculation */
  	char	   *attstorage;		/* attribute storage scheme */
  	char	   *typstorage;		/* type storage scheme */
  	bool	   *attisdropped;	/* true if attr is dropped; don't dump it */
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
***************
*** 982,988 **** psql_completion(char *text, int start, int end)
  		/* DROP ... does not work well yet */
  		static const char *const list_COLUMNALTER[] =
  		{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
! 		"DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
--- 982,989 ----
  		/* DROP ... does not work well yet */
  		static const char *const list_COLUMNALTER[] =
  		{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
! 		"DROP NOT NULL", "SET STATISTICS", "SET DISTINCT",
! 		"SET STORAGE", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
*** a/src/include/catalog/pg_attribute.h
--- b/src/include/catalog/pg_attribute.h
***************
*** 60,65 **** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS
--- 60,74 ----
  	int4		attstattarget;
  
  	/*
+ 	 * If this value is non-zero, it overrides the default ndistinct
+ 	 * computation performed by ANALYZE.  If attdistinct is positive, it
+ 	 * specifies the exact number of distinct values assumed to be present in
+ 	 * this column.  If negative, the number of distinct values is assumed to
+ 	 * be attdistinct * -.000001 * (# of rows in table).
+ 	 */
+ 	int4		attdistinct;
+ 
+ 	/*
  	 * attlen is a copy of the typlen field from pg_type for this attribute.
  	 * See atttypid comments above.
  	 */
***************
*** 176,200 **** typedef FormData_pg_attribute *Form_pg_attribute;
   * ----------------
   */
  
! #define Natts_pg_attribute				18
  #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_attacl		18
  
  
  /* ----------------
--- 185,210 ----
   * ----------------
   */
  
! #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_attstattarget 4
! #define Anum_pg_attribute_attdistinct	5
! #define Anum_pg_attribute_attlen		6
! #define Anum_pg_attribute_attnum		7
! #define Anum_pg_attribute_attndims		8
! #define Anum_pg_attribute_attcacheoff	9
! #define Anum_pg_attribute_atttypmod		10	
! #define Anum_pg_attribute_attbyval		11
! #define Anum_pg_attribute_attstorage	12
! #define Anum_pg_attribute_attalign		13
! #define Anum_pg_attribute_attnotnull	14
! #define Anum_pg_attribute_atthasdef		15
! #define Anum_pg_attribute_attisdropped	16
! #define Anum_pg_attribute_attislocal	17
! #define Anum_pg_attribute_attinhcount	18
! #define Anum_pg_attribute_attacl		19
  
  
  /* ----------------
***************
*** 212,459 **** typedef FormData_pg_attribute *Form_pg_attribute;
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},		   21, -1,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},	   16, -1,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},	   18, -1,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1,	1,	7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1,	1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1,	1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},	   18, -1,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},	   26, -1,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},	   26, -1,	4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},	   26, -1,	4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},	   24, -1,	4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},	   24, -1,	4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1,	4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},	   24, -1,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},	   24, -1,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},	   24, -1,	4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1,	4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},	   18, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1,	1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1,	4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},	   23, -1,	4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},	   23, -1,	4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1247 typname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen			21 -1 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval			16 -1 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype			18 -1 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory		18 -1 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred	16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined		16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim			18 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid			26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem			26 -1 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray			26 -1 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput			24 -1 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput		24 -1 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive		24 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend			24 -1 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin			24 -1 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout		24 -1 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze		24 -1 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign			18 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage		18 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull		16 -1 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype		26 -1 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod		23 -1 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims			23 -1 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin	25 -1 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault		25 -1 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},			19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronamespace"},		26, -1, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},			26, -1, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},			26, -1, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},		   700, -1, 4,	5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorows"},		   700, -1, 4,	6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provariadic"},		26, -1, 4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},			16, -1, 1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},		16, -1, 1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},			16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},		16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},			16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},		18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},			21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},	21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},			26, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},		30, -1, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},	  1002, -1, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},	  1009, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},		25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"prosrc"},				25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"probin"},				17, -1, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proconfig"},		  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proacl"},			  1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1255 proname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang			26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost		   700 -1 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows		   700 -1 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic		26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg			16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow		16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef		16 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict		16 -1 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset		16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile		18 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs			21 -1 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults	21 -1 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype		26 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes		30 -1 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes	  1002 -1 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames	  1009 -1 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults	25 -1 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc			25 -1 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin			17 -1 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig	  1009 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl		  1034 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},	  26, -1,	4,	1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},	  19, -1, NAMEDATALEN,	2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypid"},	  26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},		  21, -1,	2,	5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},		  21, -1,	2,	6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},	  23, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},	  23, -1,	4,	9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},	  16, -1,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1,	1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},	  18, -1,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},	  16, -1,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1,	1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1,  -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1249 attrelid			26 -1  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname			19 -1 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid			26 -1  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget	23 -1  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen			21 -1  2   5 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum			21 -1  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims			23 -1  4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff		23 -1  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod		23 -1  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval			16 -1  1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage		18 -1  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign			18 -1  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull		16 -1  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef		16 -1  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped		16 -1  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal		16 -1  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount		23 -1  4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl		  1034 -1 -1  18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},	   26, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},		   26, -1,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},	   23, -1,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},	   700, -1, 4,	9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastrelid"}, 26, -1,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relistemp"},     16, -1,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},	   18, -1,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},	   21, -1,	2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},	   21, -1,	2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1,	1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1,	1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1,	4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},		 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner			26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam			26 -1 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode		26 -1 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace	26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages			23 -1 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples	   700 -1 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid	26 -1 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid	26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex		16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared		16 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relistemp		16 -1 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind			18 -1 1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts			21 -1 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks		21 -1 2  17 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids		16 -1 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey		16 -1 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules		16 -1 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers	16 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass	16 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid		28 -1 4  23 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl		  1034 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_index
--- 222,471 ----
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},	   19, -1, 0, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnamespace"},  26, -1, 0,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},	   26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},		   21, -1, 0,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},	   16, -1, 0,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},	   18, -1, 0,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1, 0,	1,	7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1, 0,	1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1, 0,	1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},	   18, -1, 0,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},	   26, -1, 0,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},	   26, -1, 0,	4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},	   26, -1, 0,	4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},	   24, -1, 0,	4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},	   24, -1, 0,	4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1, 0,	4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},	   24, -1, 0,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},	   24, -1, 0,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},	   24, -1, 0,	4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1, 0,	4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},	   18, -1, 0,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1, 0,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1, 0,	1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1, 0,	4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},	   23, -1, 0,	4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},	   23, -1, 0,	4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, 0, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, 0, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1247 typname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen			21 -1 0 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval			16 -1 0 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype			18 -1 0 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory		18 -1 0 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred	16 -1 0 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined		16 -1 0 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim			18 -1 0 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid			26 -1 0 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem			26 -1 0 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray			26 -1 0 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput			24 -1 0 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput		24 -1 0 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive		24 -1 0 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend			24 -1 0 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin			24 -1 0 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout		24 -1 0 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze		24 -1 0 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign			18 -1 0 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage		18 -1 0 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull		16 -1 0 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype		26 -1 0 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod		23 -1 0 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims			23 -1 0 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin	25 -1 0 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault		25 -1 0 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},			19, -1, 0, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronamespace"},		26, -1, 0, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},			26, -1, 0, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},			26, -1, 0, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},		   700, -1, 0, 4,	5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorows"},		   700, -1, 0, 4,	6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provariadic"},		26, -1, 0, 4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},			16, -1, 0, 1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},		16, -1, 0, 1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},			16, -1, 0, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},		16, -1, 0, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},			16, -1, 0, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},		18, -1, 0, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},			21, -1, 0, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},	21, -1, 0, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},			26, -1, 0, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},		30, -1, 0, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, 0, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},	  1002, -1, 0, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},	  1009, -1, 0, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},		25, -1, 0, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"prosrc"},				25, -1, 0, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"probin"},				17, -1, 0, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proconfig"},		  1009, -1, 0, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proacl"},			  1034, -1, 0, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1255 proname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang			26 -1 0 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost		   700 -1 0 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows		   700 -1 0 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic		26 -1 0 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg			16 -1 0 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow		16 -1 0 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef		16 -1 0 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict		16 -1 0 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset		16 -1 0 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile		18 -1 0 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs			21 -1 0 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults	21 -1 0 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype		26 -1 0 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes		30 -1 0 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 0 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes	  1002 -1 0 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames	  1009 -1 0 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults	25 -1 0 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc			25 -1 0 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin			17 -1 0 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig	  1009 -1 0 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl		  1034 -1 0 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},	  26, -1, 0,	4,	1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},	  19, -1, 0, NAMEDATALEN,	2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypid"},	  26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1, 0,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attdistinct"},   23, -1, 0,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},		  21, -1, 0,	2,	6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},		  21, -1, 0,	2,	7, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},	  23, -1, 0,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1, 0,	4,	9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},	  23, -1, 0,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},	  16, -1, 0,	1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1, 0,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},	  18, -1, 0,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1, 0,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},	  16, -1, 0,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1, 0,	1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1, 0,	1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1, 0,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1, 0,  -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1249 attrelid			26 -1 0  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname			19 -1 0 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid			26 -1 0  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget	23 -1 0  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attdistinct		23 -1 0  4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen			21 -1 0  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum			21 -1 0  2   7 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims			23 -1 0  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff		23 -1 0  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod		23 -1 0  4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval			16 -1 0  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage		18 -1 0  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign			18 -1 0  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull		16 -1 0  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef		16 -1 0  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped		16 -1 0  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal		16 -1 0  1  17 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount		23 -1 0  4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl		  1034 -1 0 -1  19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},	   19, -1, 0, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnamespace"},  26, -1, 0,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},	   26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},	   26, -1, 0,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},		   26, -1, 0,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1, 0,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1, 0,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},	   23, -1, 0,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},	   700, -1, 0, 4,	9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastrelid"}, 26, -1, 0,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1, 0,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1, 0,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1, 0,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relistemp"},     16, -1, 0,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},	   18, -1, 0,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},	   21, -1, 0,	2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},	   21, -1, 0,	2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1, 0,	1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1, 0,	1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1, 0,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1, 0,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1, 0,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1, 0,	4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},		 1034, -1, 0, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, 0, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1259 relname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner			26 -1 0 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam			26 -1 0 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode		26 -1 0 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace	26 -1 0 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages			23 -1 0 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples	   700 -1 0 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid	26 -1 0 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid	26 -1 0 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex		16 -1 0 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared		16 -1 0 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relistemp		16 -1 0 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind			18 -1 0 1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts			21 -1 0 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks		21 -1 0 2  17 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids		16 -1 0 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey		16 -1 0 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules		16 -1 0 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers	16 -1 0 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass	16 -1 0 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid		28 -1 0 4  23 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl		  1034 -1 0 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions	  1009 -1 0 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_index
***************
*** 464,482 **** DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},		26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},			26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},			21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},		16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},		16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},	16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},		16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},		16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},		16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},			22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},			30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},			22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},			25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  #endif   /* PG_ATTRIBUTE_H */
--- 476,494 ----
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},		26, -1, 0, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},			26, -1, 0, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},			21, -1, 0, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},		16, -1, 0, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},		16, -1, 0, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},	16, -1, 0, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},		16, -1, 0, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},		16, -1, 0, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},		16, -1, 0, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},			22, -1, 0, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},			30, -1, 0, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},			22, -1, 0, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},			25, -1, 0, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},			25, -1, 0, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  #endif   /* PG_ATTRIBUTE_H */
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
***************
*** 125,131 **** typedef FormData_pg_class *Form_pg_class;
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 18 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
--- 125,131 ----
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 19 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1111,1118 **** typedef enum AlterTableType
  	AT_ColumnDefault,			/* alter column default */
  	AT_DropNotNull,				/* alter column drop not null */
  	AT_SetNotNull,				/* alter column set not null */
! 	AT_SetStatistics,			/* alter column statistics */
! 	AT_SetStorage,				/* alter column storage */
  	AT_DropColumn,				/* drop column */
  	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
  	AT_AddIndex,				/* add index */
--- 1111,1119 ----
  	AT_ColumnDefault,			/* alter column default */
  	AT_DropNotNull,				/* alter column drop not null */
  	AT_SetNotNull,				/* alter column set not null */
! 	AT_SetStatistics,			/* alter column set statistics */
! 	AT_SetDistinct,				/* alter column set distinct */
! 	AT_SetStorage,				/* alter column set storage */
  	AT_DropColumn,				/* drop column */
  	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
  	AT_AddIndex,				/* add index */
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#1)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

Per previous discussion.
http://archives.postgresql.org/message-id/8066.1229106059@sss.pgh.pa.us
http://archives.postgresql.org/message-id/603c8f070904021926g92eb55sdfc68141133957c1@mail.gmail.com

I'm not thrilled about adding a column to pg_attribute for this.
Isn't there some way of keeping it in pg_statistic?

regards, tom lane

#3Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#2)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sat, Apr 4, 2009 at 7:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Per previous discussion.
http://archives.postgresql.org/message-id/8066.1229106059@sss.pgh.pa.us
http://archives.postgresql.org/message-id/603c8f070904021926g92eb55sdfc68141133957c1@mail.gmail.com

I'm not thrilled about adding a column to pg_attribute for this.
Isn't there some way of keeping it in pg_statistic?

I don't like the idea of keeping it in pg_statistic. Right now, all
of the data in pg_statistic is transient, so you could theoretically
truncate the table at any time without losing anything permanent.
It's true that we don't do that right now, but it seems cleaner to
keep the data generated by the analyzer separate from the stuff we
consider part of the structure of the database. If we did put the
data in pg_statistic, then we'd have to teach vacuum that when it
writes out new statistics, it also has to copy over this setting from
the previous version of the tuple. And that means it would have to
lock the tuples against concurrent updates while analyze is running.
Also, if someone happened to run ALTER TABLE SET DISTINCT before the
first run of ANALYZE on that table (for example, during pg_load)
there'd be no existing row in pg_statistic for the DDL command to
update, so we'd need to create and insert a fake row (which,
incidentally, would blow up any concurrent ANALYZE already in progress
when it got and tried to insert the resulting rows into pg_statistic,
violating the unique constraint). All in all it seems rather messy.

What is the specific nature of your concern? I thought about the
possibility of a distributed performance penalty that might be
associated with enlarging pg_attribute, but increasing the size of a
structure that is already 112 bytes by another 4 doesn't seem likely
to be significant, especially since we're not crossing a power-of-two
boundary. It might be possible to reclaim 4 bytes by changing
attstattarget and attndims from int4 to int2, but I'd rather do that
as a separate patch.

...Robert

#4Alvaro Herrera
alvherre@commandprompt.com
In reply to: Robert Haas (#3)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas escribi�:

On Sat, Apr 4, 2009 at 7:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Per previous discussion.
http://archives.postgresql.org/message-id/8066.1229106059@sss.pgh.pa.us
http://archives.postgresql.org/message-id/603c8f070904021926g92eb55sdfc68141133957c1@mail.gmail.com

I'm not thrilled about adding a column to pg_attribute for this.
Isn't there some way of keeping it in pg_statistic?

I don't like the idea of keeping it in pg_statistic. Right now, all
of the data in pg_statistic is transient, so you could theoretically
truncate the table at any time without losing anything permanent.

Maybe use a new catalog?

What is the specific nature of your concern? I thought about the
possibility of a distributed performance penalty that might be
associated with enlarging pg_attribute, but increasing the size of a
structure that is already 112 bytes by another 4 doesn't seem likely
to be significant, especially since we're not crossing a power-of-two
boundary.

FWIW it has been said that whoever is concerned about pg_attribute bloat
should be first looking at getting rid of the redundant entries for
system columns, for each and every table.

--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#4)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Alvaro Herrera <alvherre@commandprompt.com> writes:

FWIW it has been said that whoever is concerned about pg_attribute bloat
should be first looking at getting rid of the redundant entries for
system columns, for each and every table.

That's been overtaken by events, unfortunately: we now need those
entries to carry per-column permissions on system columns. So they're
no longer merely overhead.

Possibly we could hack things so that only system columns with
non-default permissions are actually stored, but that feels like
a kluge.

regards, tom lane

#6Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#4)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sat, Apr 4, 2009 at 10:31 PM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:

Robert Haas escribió:

On Sat, Apr 4, 2009 at 7:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Per previous discussion.
http://archives.postgresql.org/message-id/8066.1229106059@sss.pgh.pa.us
http://archives.postgresql.org/message-id/603c8f070904021926g92eb55sdfc68141133957c1@mail.gmail.com

I'm not thrilled about adding a column to pg_attribute for this.
Isn't there some way of keeping it in pg_statistic?

I don't like the idea of keeping it in pg_statistic.  Right now, all
of the data in pg_statistic is transient, so you could theoretically
truncate the table at any time without losing anything permanent.

Maybe use a new catalog?

If we go that route, we would probably make sense to move
attstattarget there as well. Obviously it wouldn't make sense to move
anything that's in the critical path of ordinary database operations,
but maybe attislocal or attinhcount could be moved as well. But I'm
not sure it's really warranted because, AFAIK, we have no evidence
that this is a real as opposed to a theoretical problem, and even if
we moved all of that stuff, that's only 12 bytes, and now you have
another table that's competing for space in the system cache. If
someone could demonstrate (say, by reducing NAMEDATALEN) that a
smaller pg_attribute structure would generate a real performance
benefit, then it would be worth spending the time to figure out a way
to make that happen (obviously without actually reducing NAMEDATALEN,
that's only a possible way to measure the impact).

What is the specific nature of your concern?  I thought about the
possibility of a distributed performance penalty that might be
associated with enlarging pg_attribute, but increasing the size of a
structure that is already 112 bytes by another 4 doesn't seem likely
to be significant, especially since we're not crossing a power-of-two
boundary.

FWIW it has been said that whoever is concerned about pg_attribute bloat
should be first looking at getting rid of the redundant entries for BN
system columns, for each and every table.

That's a different kind of bloat (more rows vs. larger rows) but a
valid point all the same. I suspect neither type has much practical
impact, and that if we listed all the performance problems that
PostgreSQL has today, neither would be in the top 500. Bad ndistinct
estimates would be, however.

...Robert

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#3)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

On Sat, Apr 4, 2009 at 7:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm not thrilled about adding a column to pg_attribute for this.

What is the specific nature of your concern?

Actually, I'm more worried about the TupleDesc data structure than
the catalogs. There are TupleDescs all over the backend, and I've
seen evidence in profiles that setting them up is a nontrivial cost.

You're very possibly right that four more bytes is in the noise,
though.

Two other comments now that I've read a little further:

* This isn't happening for 8.4, so adjust the pg_dump code.

* Using an integer is bogus. Use a float4 and forget the weird scaling;
it should have exactly the same interpretation as stadistinct, except
for 0 meaning "unset" instead of "unknown".

regards, tom lane

#8Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#7)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sat, Apr 4, 2009 at 11:14 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Sat, Apr 4, 2009 at 7:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm not thrilled about adding a column to pg_attribute for this.

What is the specific nature of your concern?

Actually, I'm more worried about the TupleDesc data structure than
the catalogs.  There are TupleDescs all over the backend, and I've
seen evidence in profiles that setting them up is a nontrivial cost.

You're very possibly right that four more bytes is in the noise,
though.

Two other comments now that I've read a little further:

* This isn't happening for 8.4, so adjust the pg_dump code.

I thought about writing 80500, but the effect of that would have been
to render the patch impossible to test, so I didn't. :-)

I think I'll be very lucky if that's the most bitrot this accumulates
between now and when the tree is open for 8.5 development. System
catalog changes stink in that regard. I suppose we could tag and
branch the tree now, but that would just move the work of fixing any
subsequent conflicts from patch authors to committers, which is sort
of a zero-sum game.

* Using an integer is bogus.  Use a float4 and forget the weird scaling;
it should have exactly the same interpretation as stadistinct, except
for 0 meaning "unset" instead of "unknown".

I think there's a pretty good chance that will lead to a complaint
that is some variant of the following: "I ran this command and then I
did a pg_dump and the output doesn't match what I put in." Or maybe,
"I did a dump and a restore on a different machine with a different
architecture and then another dump and then I diffed them and this
popped out."

I have a deep-seated aversion to storing important values as float,
and we seem to have no other floats anywhere in our DDL, so I was a
little leery about breaking new ground. There's nothing particularly
special about the scaling that the pg_statistic stuff uses, and it's
basically pretty obscure internal stuff anyway, so I think the
consistency argument is fairly weak.

...Robert

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#8)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

On Sat, Apr 4, 2009 at 11:14 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

* Using an integer is bogus. �Use a float4 and forget the weird scaling;
it should have exactly the same interpretation as stadistinct, except
for 0 meaning "unset" instead of "unknown".

I have a deep-seated aversion to storing important values as float,

[ shrug... ] Precision is not important for this value: we are not
anywhere near needing more than six significant digits for our
statistical estimates. Range, on the other hand, could be important
when dealing with really large tables. So I'm much more concerned
about whether the definition is too restrictive than about whether
some uninformed person complains about exactness.

regards, tom lane

#10Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#9)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Apr 5, 2009 at 7:56 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Sat, Apr 4, 2009 at 11:14 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

* Using an integer is bogus.  Use a float4 and forget the weird scaling;
it should have exactly the same interpretation as stadistinct, except
for 0 meaning "unset" instead of "unknown".

I have a deep-seated aversion to storing important values as float,

[ shrug... ]  Precision is not important for this value: we are not
anywhere near needing more than six significant digits for our
statistical estimates.  Range, on the other hand, could be important
when dealing with really large tables.  So I'm much more concerned
about whether the definition is too restrictive than about whether
some uninformed person complains about exactness.

I thought about that, and if you think that's better, I can implement
it that way. Personally, I'm unconvinced. The use case for
specifying a number of distinct values in excess of 2 billion as an
absolute number rather than as a percentage of the table size seems
pretty weak to me. I would rather use integers and have it be clean.
But I would rather have it your way than not have it at all.

...Robert

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#10)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

On Sun, Apr 5, 2009 at 7:56 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

[ shrug... ] �Precision is not important for this value: we are not
anywhere near needing more than six significant digits for our
statistical estimates. �Range, on the other hand, could be important
when dealing with really large tables.

I thought about that, and if you think that's better, I can implement
it that way. Personally, I'm unconvinced. The use case for
specifying a number of distinct values in excess of 2 billion as an
absolute number rather than as a percentage of the table size seems
pretty weak to me.

I was more concerned about the other end of it. Your patch sets a
not-too-generous lower bound on the percentage that can be represented ...

regards, tom lane

#12Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#11)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Apr 5, 2009 at 10:00 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Sun, Apr 5, 2009 at 7:56 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

[ shrug... ]  Precision is not important for this value: we are not
anywhere near needing more than six significant digits for our
statistical estimates.  Range, on the other hand, could be important
when dealing with really large tables.

I thought about that, and if you think that's better, I can implement
it that way.  Personally, I'm unconvinced.  The use case for
specifying a number of distinct values in excess of 2 billion as an
absolute number rather than as a percentage of the table size seems
pretty weak to me.

I was more concerned about the other end of it.  Your patch sets a
not-too-generous lower bound on the percentage that can be represented ...

Huh? With a scaling factor of 1 million, you can represent anything
down to about 0.000001, which is apparently all you can expect out of
a float4 anyway.

http://archives.postgresql.org/pgsql-bugs/2009-01/msg00039.php

In fact, we could change the scaling factor to 1 billion if you like,
and it would then give you MORE significant digits than you'll get out
of a float4 (and you'll be able to predict the exact number that
you're gonna get). If someone has billions of rows in the table but
only thousands of distinct values, I would expect them to run a script
to count 'em up and specify the exact number, rather than specifying
some microscopic percentage. But there's certainly enough range in
int4 to tack on three more decimal places if you think it's warranted.

(It's also worth pointing out that the calculations we do with
ndistinct are pretty approximations anyway. If the difference between
stadistinct = -1 x 10^-6 and stadistinct = -1.4^10-6 is the thing
that's determining whether the planner is picking the correct plan on
your 4-billion-row table, you probably want to tune some other
parameter as well so as to get further away from that line. Just
getting the value in the ballpark should be a big improvement over how
things stand now.)

...Robert

#13Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#12)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Apr 5, 2009 at 10:38 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Sun, Apr 5, 2009 at 10:00 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Sun, Apr 5, 2009 at 7:56 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

[ shrug... ]  Precision is not important for this value: we are not
anywhere near needing more than six significant digits for our
statistical estimates.  Range, on the other hand, could be important
when dealing with really large tables.

I thought about that, and if you think that's better, I can implement
it that way.  Personally, I'm unconvinced.  The use case for
specifying a number of distinct values in excess of 2 billion as an
absolute number rather than as a percentage of the table size seems
pretty weak to me.

I was more concerned about the other end of it.  Your patch sets a
not-too-generous lower bound on the percentage that can be represented ...

Huh?  With a scaling factor of 1 million, you can represent anything
down to about 0.000001, which is apparently all you can expect out of
a float4 anyway.

http://archives.postgresql.org/pgsql-bugs/2009-01/msg00039.php

I guess I'm wrong here - 0.00001 is only one SIGNIFICANT digit. But
the point remains that specifying ndistinct in ppm is probably enough
for most cases, and ppb (which would still fit in int4) even more so.
I don't think we need to worry about people with trillions of rows
(and even they could still specify an absolute number).

...Robert

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#12)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

(It's also worth pointing out that the calculations we do with
ndistinct are pretty approximations anyway. If the difference between
stadistinct = -1 x 10^-6 and stadistinct = -1.4^10-6 is the thing
that's determining whether the planner is picking the correct plan on
your 4-billion-row table,

No, it's the loss of ability to set stadistinct to -1e-9 or -1e-12 or
-1e-15 or so that is bothering me. In a table with billions of rows
that could become important.

Or maybe not; but the real bottom line here is that it is 100% silly to
use a different representation in this column than is used in the
underlying stadistinct column. All you accomplish by that is to impose
on the user the intersection of the accuracy/range limits of the two
different representations.

regards, tom lane

#15Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#14)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Apr 5, 2009 at 11:33 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

(It's also worth pointing out that the calculations we do with
ndistinct are pretty approximations anyway.  If the difference between
stadistinct = -1 x 10^-6 and stadistinct = -1.4^10-6 is the thing
that's determining whether the planner is picking the correct plan on
your 4-billion-row table,

No, it's the loss of ability to set stadistinct to -1e-9 or -1e-12 or
-1e-15 or so that is bothering me.  In a table with billions of rows
that could become important.

Or maybe not; but the real bottom line here is that it is 100% silly to
use a different representation in this column than is used in the
underlying stadistinct column.  All you accomplish by that is to impose
on the user the intersection of the accuracy/range limits of the two
different representations.

Well, I think I was pretty clear about what I was trying to
accomplish. I think there are more people who care about pg_dump
output being diffable than there are who need to set ndistinct more
accurately than 1 ppm and yet not as an integer. Perhaps if any of
those people are reading this thread they could chime in. Otherwise,
I will implement as you propose.

...Robert

#16Stephen Frost
sfrost@snowman.net
In reply to: Robert Haas (#15)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

* Robert Haas (robertmhaas@gmail.com) wrote:

Well, I think I was pretty clear about what I was trying to
accomplish. I think there are more people who care about pg_dump
output being diffable than there are who need to set ndistinct more
accurately than 1 ppm and yet not as an integer. Perhaps if any of
those people are reading this thread they could chime in. Otherwise,
I will implement as you propose.

I do such diffs pretty often, but I don't think I've *ever* done it on
catalog tables.. Perhaps it'll come up in the future, but I doubt it.

Stephen

#17Robert Haas
robertmhaas@gmail.com
In reply to: Stephen Frost (#16)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Mon, Apr 6, 2009 at 7:30 AM, Stephen Frost <sfrost@snowman.net> wrote:

* Robert Haas (robertmhaas@gmail.com) wrote:

Well, I think I was pretty clear about what I was trying to
accomplish.  I think there are more people who care about pg_dump
output being diffable than there are who need to set ndistinct more
accurately than 1 ppm and yet not as an integer.  Perhaps if any of
those people are reading this thread they could chime in.  Otherwise,
I will implement as you propose.

I do such diffs pretty often, but I don't think I've *ever* done it on
catalog tables..  Perhaps it'll come up in the future, but I doubt it.

       Stephen

Well the point is when you dump a user table, it will dump this
setting along with it, same as it does now for statistics_target. So
if you diff the DDL you might see differences in rounding. If you
only diff the data, it won't matter unless, as you say, you're dumping
pg_attribute itself.

...Robert

#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#15)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

Well, I think I was pretty clear about what I was trying to
accomplish. I think there are more people who care about pg_dump
output being diffable than there are who need to set ndistinct more
accurately than 1 ppm and yet not as an integer.

My, you *are* paranoid about float4 aren't you? Once you've stored
a given value, it's always going to dump the same. Diffing different
dumps isn't going to be a problem. I concede that it might look
different from what you put in originally, but we make no effort to
guarantee that for DDL anyway.

(It is true that with pg_dump's default float_extra_digits setting,
outputs from this column might look uglier than they need to.
I don't see anything wrong with having pg_dump forcibly round the
value to five or so digits, though.)

regards, tom lane

#19Stephen Frost
sfrost@snowman.net
In reply to: Robert Haas (#17)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert,

* Robert Haas (robertmhaas@gmail.com) wrote:

On Mon, Apr 6, 2009 at 7:30 AM, Stephen Frost <sfrost@snowman.net> wrote:

I do such diffs pretty often, but I don't think I've *ever* done it on
catalog tables..  Perhaps it'll come up in the future, but I doubt it.

Well the point is when you dump a user table, it will dump this
setting along with it, same as it does now for statistics_target. So
if you diff the DDL you might see differences in rounding. If you
only diff the data, it won't matter unless, as you say, you're dumping
pg_attribute itself.

The rounding when you dump it out is going to be consistant though, is
it not? I mean, you might get a difference between what you try to set
it to and the result that you get from pg_dump, but if you compare one
pg_dump to another done later there shouldn't be any change, right? If
there is an architecture difference then I could maybe see it, but I
thought float-handling was well-defined on systems we run on.

Thanks,

Stephen

#20Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#18)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Mon, Apr 6, 2009 at 10:49 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Well, I think I was pretty clear about what I was trying to
accomplish.  I think there are more people who care about pg_dump
output being diffable than there are who need to set ndistinct more
accurately than 1 ppm and yet not as an integer.

My, you *are* paranoid about float4 aren't you?

Yes - perhaps unreasonably so. I've had so many bad experiences with
floating-point arithmetic that I've stopped trying to understand all
of the crazy things that can happen and started just avoiding it like
the plague. Long live numeric!

Once you've stored
a given value, it's always going to dump the same.  Diffing different
dumps isn't going to be a problem.  I concede that it might look
different from what you put in originally, but we make no effort to
guarantee that for DDL anyway.

(It is true that with pg_dump's default float_extra_digits setting,
outputs from this column might look uglier than they need to.
I don't see anything wrong with having pg_dump forcibly round the
value to five or so digits, though.)

So based on this comment and Stephen's remarks, I'm going to assume
that I'm succumbing to a fit of unjustified paranoia and re-implement
as you suggest.

...Robert

#21Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#20)
1 attachment(s)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Mon, Apr 6, 2009 at 11:15 AM, Robert Haas <robertmhaas@gmail.com> wrote:

So based on this comment and Stephen's remarks, I'm going to assume
that I'm succumbing to a fit of unjustified paranoia and re-implement
as you suggest.

OK, new version of patch, this time with the weird scaling removed and
the datatype changed to float4.

I have not changed the minimum value for remoteVersion in pg_dump.c,
as that would make the patch not able to be tested now. So that line
and the comment two lines following will need to be updated prior to
application. Also requires catversion bump.

...Robert

Attachments:

ndistinct-2.patchtext/x-diff; charset=US-ASCII; name=ndistinct-2.patchDownload
*** a/doc/src/sgml/ref/alter_table.sgml
--- b/doc/src/sgml/ref/alter_table.sgml
***************
*** 39,44 **** where <replaceable class="PARAMETER">action</replaceable> is one of:
--- 39,45 ----
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
+     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DISTINCT<replaceable class="PARAMETER">floating point</replaceable>
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
      ADD <replaceable class="PARAMETER">table_constraint</replaceable>
      DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
***************
*** 154,159 **** where <replaceable class="PARAMETER">action</replaceable> is one of:
--- 155,186 ----
     </varlistentry>
  
     <varlistentry>
+     <term><literal>SET DISTINCT</literal></term>
+     <listitem>
+      <para>
+       This form can be used to override the result of the ndistinct computation
+       performed by subsequent
+       <xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
+       When set to a positive value, ANALYZE will assume that the column
+       contains exactly the specified number of distinct values (even if its
+       own analysis indicates otherwie).  When set to a negative value, which
+       must be greater than or equal to -1, it will assume that the
+       number of distinct values in the column is linear in the size of the
+       table, and will compute the exact value by multiplying the estimated
+       table size by the absolute value of the number specified.  This can
+       be useful when the size of the table changes over time; the
+       multiplication by the number of rows in the table is not performed until
+       query planning time.
+       Use a value of 0 to revert to computing the number of distinct values
+       normally.
+       For more information on the use of statistics by the
+       <productname>PostgreSQL</productname> query planner, refer to
+       <xref linkend="planner-stats">.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <indexterm>
       <primary>TOAST</primary>
       <secondary>per-column storage settings</secondary>
*** a/doc/src/sgml/ref/analyze.sgml
--- b/doc/src/sgml/ref/analyze.sgml
***************
*** 160,165 **** ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> [ ( <re
--- 160,175 ----
    </para>
  
    <para>
+    The analyzer also estimates the number of distinct values that appear
+    in each column.  Because only a subset of pages are scanned, this method
+    can sometimes be quite inaccurate, especially for large tables.  If this
+    inaccuracy leads to bad query plans, the analyzer can be forced to use
+    a more correct value with <command>ALTER TABLE ... ALTER COLUMN ... SET
+    STATISTICS</command> (see <xref linkend="sql-altertable"
+    endterm="sql-altertable-title">).
+   </para>
+ 
+   <para>
     The largest statistics target among the columns being analyzed determines
     the number of table rows sampled to prepare the statistics.  Increasing
     the target causes a proportional increase in the time and space needed
*** a/src/backend/access/common/tupdesc.c
--- b/src/backend/access/common/tupdesc.c
***************
*** 338,343 **** equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
--- 338,345 ----
  			return false;
  		if (attr1->attstattarget != attr2->attstattarget)
  			return false;
+ 		if (attr1->attdistinct != attr2->attdistinct)
+ 			return false;
  		if (attr1->attlen != attr2->attlen)
  			return false;
  		if (attr1->attndims != attr2->attndims)
***************
*** 465,470 **** TupleDescInitEntry(TupleDesc desc,
--- 467,473 ----
  		MemSet(NameStr(att->attname), 0, NAMEDATALEN);
  
  	att->attstattarget = -1;
+ 	att->attdistinct = 0;
  	att->attcacheoff = -1;
  	att->atttypmod = typmod;
  
*** a/src/backend/bootstrap/bootstrap.c
--- b/src/backend/bootstrap/bootstrap.c
***************
*** 743,748 **** DefineAttr(char *name, char *type, int attnum)
--- 743,749 ----
  	}
  
  	attrtypes[attnum]->attstattarget = -1;
+ 	attrtypes[attnum]->attdistinct = 0;
  	attrtypes[attnum]->attcacheoff = -1;
  	attrtypes[attnum]->atttypmod = -1;
  	attrtypes[attnum]->attislocal = true;
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 111,147 **** static List *insert_ordered_unique_oid(List *list, Oid datum);
   */
  
  static FormData_pg_attribute a1 = {
! 	0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
  	SelfItemPointerAttributeNumber, 0, -1, -1,
  	false, 'p', 's', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a2 = {
! 	0, {"oid"}, OIDOID, 0, sizeof(Oid),
  	ObjectIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a3 = {
! 	0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
  	MinTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a4 = {
! 	0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
  	MinCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a5 = {
! 	0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
  	MaxTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a6 = {
! 	0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
  	MaxCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
--- 111,147 ----
   */
  
  static FormData_pg_attribute a1 = {
! 	0, {"ctid"}, TIDOID, 0, 0, sizeof(ItemPointerData),
  	SelfItemPointerAttributeNumber, 0, -1, -1,
  	false, 'p', 's', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a2 = {
! 	0, {"oid"}, OIDOID, 0, 0, sizeof(Oid),
  	ObjectIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a3 = {
! 	0, {"xmin"}, XIDOID, 0, 0, sizeof(TransactionId),
  	MinTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a4 = {
! 	0, {"cmin"}, CIDOID, 0, 0, sizeof(CommandId),
  	MinCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a5 = {
! 	0, {"xmax"}, XIDOID, 0, 0, sizeof(TransactionId),
  	MaxTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a6 = {
! 	0, {"cmax"}, CIDOID, 0, 0, sizeof(CommandId),
  	MaxCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
***************
*** 153,159 **** static FormData_pg_attribute a6 = {
   * 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, { 0 }
  };
--- 153,159 ----
   * used in SQL.
   */
  static FormData_pg_attribute a7 = {
! 	0, {"tableoid"}, OIDOID, 0, 0, sizeof(Oid),
  	TableOidAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
***************
*** 514,519 **** InsertPgAttributeTuple(Relation pg_attribute_rel,
--- 514,520 ----
  	values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
  	values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
  	values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
+ 	values[Anum_pg_attribute_attdistinct - 1] = Float8GetDatum(new_attribute->attdistinct);
  
  	/* start out with empty permissions */
  	nulls[Anum_pg_attribute_attacl - 1] = true;
***************
*** 570,575 **** AddNewAttributeTuples(Oid new_rel_oid,
--- 571,577 ----
  		attr->attrelid = new_rel_oid;
  		/* Make sure these are OK, too */
  		attr->attstattarget = -1;
+ 		attr->attdistinct = 0;
  		attr->attcacheoff = -1;
  
  		InsertPgAttributeTuple(rel, attr, indstate);
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 187,192 **** ConstructTupleDescriptor(Relation heapRelation,
--- 187,193 ----
  			to->attnum = i + 1;
  
  			to->attstattarget = -1;
+ 			to->attdistinct = 0;
  			to->attcacheoff = -1;
  			to->attnotnull = false;
  			to->atthasdef = false;
*** a/src/backend/commands/analyze.c
--- b/src/backend/commands/analyze.c
***************
*** 434,439 **** analyze_rel(Oid relid, VacuumStmt *vacstmt,
--- 434,448 ----
  									 std_fetch_func,
  									 numrows,
  									 totalrows);
+ 
+ 			/*
+ 			 * If the user has overridden the result of our stadistinct
+ 			 * calculation using ALTER TABLE ... ALTER COLUMN ... SET DISTINCT,
+ 			 * fill in the override value now.
+ 			 */
+ 			if (stats->attr->attdistinct != 0)
+ 				stats->stadistinct = stats->attr->attdistinct;
+ 
  			MemoryContextResetAndDeleteChildren(col_context);
  		}
  
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 283,288 **** static void ATPrepSetStatistics(Relation rel, const char *colName,
--- 283,290 ----
  					Node *flagValue);
  static void ATExecSetStatistics(Relation rel, const char *colName,
  					Node *newValue);
+ static void ATExecSetDistinct(Relation rel, const char *colName,
+ 				 Node *newValue);
  static void ATExecSetStorage(Relation rel, const char *colName,
  				 Node *newValue);
  static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
***************
*** 2401,2406 **** ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
--- 2403,2414 ----
  			ATPrepSetStatistics(rel, cmd->name, cmd->def);
  			pass = AT_PASS_COL_ATTRS;
  			break;
+ 		case AT_SetDistinct:	/* ALTER COLUMN STATISTICS */
+ 			ATSimplePermissions(rel, false);
+ 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
+ 			/* No command-specific prep needed */
+ 			pass = AT_PASS_COL_ATTRS;
+ 			break;
  		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATSimplePermissions(rel, false);
  			ATSimpleRecursion(wqueue, rel, cmd, recurse);
***************
*** 2610,2619 **** ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
  		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATExecSetNotNull(tab, rel, cmd->name);
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN STATISTICS */
  			ATExecSetStatistics(rel, cmd->name, cmd->def);
  			break;
! 		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATExecSetStorage(rel, cmd->name, cmd->def);
  			break;
  		case AT_DropColumn:		/* DROP COLUMN */
--- 2618,2630 ----
  		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATExecSetNotNull(tab, rel, cmd->name);
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
  			ATExecSetStatistics(rel, cmd->name, cmd->def);
  			break;
! 		case AT_SetDistinct:	/* ALTER COLUMN SET DISTINCT */
! 			ATExecSetDistinct(rel, cmd->name, cmd->def);
! 			break;
! 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
  			ATExecSetStorage(rel, cmd->name, cmd->def);
  			break;
  		case AT_DropColumn:		/* DROP COLUMN */
***************
*** 4075,4080 **** ATExecSetStatistics(Relation rel, const char *colName, Node *newValue)
--- 4086,4157 ----
  }
  
  /*
+  * ALTER TABLE ALTER COLUMN SET DISTINCT
+  */
+ static void
+ ATExecSetDistinct(Relation rel, const char *colName, Node *newValue)
+ {
+ 	float4		newdistinct;
+ 	Relation	attrelation;
+ 	HeapTuple	tuple;
+ 	Form_pg_attribute attrtuple;
+ 
+ 	switch (nodeTag(newValue))
+ 	{
+ 		case T_Integer:
+ 			newdistinct = intVal(newValue);
+ 			break;
+ 		case T_Float:
+ 			newdistinct = floatVal(newValue);
+ 			break;
+ 		default:
+ 			elog(ERROR, "unrecognized node type: %d",
+ 				 (int) nodeTag(newValue));
+ 			/* keep compiler quiet */
+ 			newdistinct = 0;
+ 	}
+ 
+ 	/*
+ 	 * Limit target to a sane range
+ 	 */
+ 	if (newdistinct < -1.0)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				 errmsg("number of distinct values %f is too low",
+ 						newdistinct)));
+ 	}
+ 
+ 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
+ 
+ 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_COLUMN),
+ 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
+ 						colName, RelationGetRelationName(rel))));
+ 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
+ 
+ 	if (attrtuple->attnum <= 0)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot alter system column \"%s\"",
+ 						colName)));
+ 
+ 	attrtuple->attdistinct = newdistinct;
+ 
+ 	simple_heap_update(attrelation, &tuple->t_self, tuple);
+ 
+ 	/* keep system catalog indexes current */
+ 	CatalogUpdateIndexes(attrelation, tuple);
+ 
+ 	heap_freetuple(tuple);
+ 
+ 	heap_close(attrelation, RowExclusiveLock);
+ }
+ 
+ /*
   * ALTER TABLE ALTER COLUMN SET STORAGE
   */
  static void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 1584,1589 **** alter_table_cmd:
--- 1584,1598 ----
  					n->def = (Node *) makeInteger($6);
  					$$ = (Node *)n;
  				}
+ 			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET DISTINCT <SignedIconst> */
+ 			| ALTER opt_column ColId SET DISTINCT NumericOnly
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_SetDistinct;
+ 					n->name = $3;
+ 					n->def = (Node *) $6;
+ 					$$ = (Node *)n;
+ 				}
  			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
  			| ALTER opt_column ColId SET STORAGE ColId
  				{
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 4637,4642 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4637,4643 ----
  	int			i_atttypname;
  	int			i_atttypmod;
  	int			i_attstattarget;
+ 	int			i_attdistinct;
  	int			i_attstorage;
  	int			i_typstorage;
  	int			i_attnotnull;
***************
*** 4682,4688 **** getTableAttrs(TableInfo *tblinfo, int numTables)
  
  		resetPQExpBuffer(q);
  
! 		if (g_fout->remoteVersion >= 70300)
  		{
  			/* need left join here to not fail on dropped columns ... */
  			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
--- 4683,4705 ----
  
  		resetPQExpBuffer(q);
  
! 		if (g_fout->remoteVersion >= 80400)
! 		{
! 			/* attdistinct doesn't exist prior to 8.4 */
! 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
! 								 "a.attstattarget, a.attdistinct, "
! 								 "a.attstorage, t.typstorage, a.attnotnull, "
! 								 "a.atthasdef, a.attisdropped, a.attlen, "
! 								 "a.attalign, a.attislocal, "
! 				   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
! 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
! 							  "ON a.atttypid = t.oid "
! 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
! 							  "AND a.attnum > 0::pg_catalog.int2 "
! 							  "ORDER BY a.attrelid, a.attnum",
! 							  tbinfo->dobj.catId.oid);
! 		}
! 		else if (g_fout->remoteVersion >= 70300)
  		{
  			/* need left join here to not fail on dropped columns ... */
  			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
***************
*** 4744,4749 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4761,4767 ----
  		i_atttypname = PQfnumber(res, "atttypname");
  		i_atttypmod = PQfnumber(res, "atttypmod");
  		i_attstattarget = PQfnumber(res, "attstattarget");
+ 		i_attdistinct = PQfnumber(res, "attdistinct");
  		i_attstorage = PQfnumber(res, "attstorage");
  		i_typstorage = PQfnumber(res, "typstorage");
  		i_attnotnull = PQfnumber(res, "attnotnull");
***************
*** 4758,4763 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4776,4782 ----
  		tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
  		tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
  		tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
+ 		tbinfo->attdistinct = (char **) malloc(ntups * sizeof(char *));
  		tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
  		tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
  		tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
***************
*** 4783,4788 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4802,4808 ----
  			tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
  			tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
  			tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
+ 			tbinfo->attdistinct[j] = strdup(PQgetvalue(res, j, i_attdistinct));
  			tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
  			tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
  			tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
***************
*** 9938,9943 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
--- 9958,9979 ----
  			}
  
  			/*
+ 			 * Dump per-column distinct information. We only issue an ALTER
+ 			 * TABLE statement if the attdistinct entry for this column is
+ 			 * non-zero (i.e. it's not the default value)
+ 			 */
+ 			if (atof(tbinfo->attdistinct[j]) != 0 &&
+ 				!tbinfo->attisdropped[j])
+ 			{
+ 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
+ 								  fmtId(tbinfo->dobj.name));
+ 				appendPQExpBuffer(q, "ALTER COLUMN %s SET DISTINCT ",
+ 								  fmtId(tbinfo->attnames[j]));
+ 				appendStringLiteralAH(q, tbinfo->attdistinct[j], fout);
+ 				appendPQExpBuffer(q, ";\n");
+ 			}
+ 
+ 			/*
  			 * Dump per-column storage information.  The statement is only
  			 * dumped if the storage has been changed from the type's default.
  			 */
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
***************
*** 243,248 **** typedef struct _tableInfo
--- 243,249 ----
  	char	  **atttypnames;	/* attribute type names */
  	int		   *atttypmod;		/* type-specific type modifiers */
  	int		   *attstattarget;	/* attribute statistics targets */
+ 	char	  **attdistinct;	/* override ndistinct calculation */
  	char	   *attstorage;		/* attribute storage scheme */
  	char	   *typstorage;		/* type storage scheme */
  	bool	   *attisdropped;	/* true if attr is dropped; don't dump it */
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
***************
*** 970,976 **** psql_completion(char *text, int start, int end)
  		/* DROP ... does not work well yet */
  		static const char *const list_COLUMNALTER[] =
  		{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
! 		"DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
--- 970,977 ----
  		/* DROP ... does not work well yet */
  		static const char *const list_COLUMNALTER[] =
  		{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
! 		"DROP NOT NULL", "SET STATISTICS", "SET DISTINCT",
! 		"SET STORAGE", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
*** a/src/include/catalog/pg_attribute.h
--- b/src/include/catalog/pg_attribute.h
***************
*** 60,65 **** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS
--- 60,74 ----
  	int4		attstattarget;
  
  	/*
+ 	 * If this value is non-zero, it overrides the default ndistinct
+ 	 * computation performed by ANALYZE.  If attdistinct is positive, it
+ 	 * specifies the exact number of distinct values assumed to be present in
+ 	 * this column.  If negative, the number of distinct values is assumed to
+ 	 * be attdistinct * -1.0 * (# of rows in table).
+ 	 */
+ 	float4		attdistinct;
+ 
+ 	/*
  	 * attlen is a copy of the typlen field from pg_type for this attribute.
  	 * See atttypid comments above.
  	 */
***************
*** 176,200 **** typedef FormData_pg_attribute *Form_pg_attribute;
   * ----------------
   */
  
! #define Natts_pg_attribute				18
  #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_attacl		18
  
  
  /* ----------------
--- 185,210 ----
   * ----------------
   */
  
! #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_attstattarget 4
! #define Anum_pg_attribute_attdistinct	5
! #define Anum_pg_attribute_attlen		6
! #define Anum_pg_attribute_attnum		7
! #define Anum_pg_attribute_attndims		8
! #define Anum_pg_attribute_attcacheoff	9
! #define Anum_pg_attribute_atttypmod		10
! #define Anum_pg_attribute_attbyval		11
! #define Anum_pg_attribute_attstorage	12
! #define Anum_pg_attribute_attalign		13
! #define Anum_pg_attribute_attnotnull	14
! #define Anum_pg_attribute_atthasdef		15
! #define Anum_pg_attribute_attisdropped	16
! #define Anum_pg_attribute_attislocal	17
! #define Anum_pg_attribute_attinhcount	18
! #define Anum_pg_attribute_attacl		19
  
  
  /* ----------------
***************
*** 212,459 **** typedef FormData_pg_attribute *Form_pg_attribute;
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},		   21, -1,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},	   16, -1,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},	   18, -1,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1,	1,	7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1,	1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1,	1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},	   18, -1,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},	   26, -1,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},	   26, -1,	4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},	   26, -1,	4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},	   24, -1,	4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},	   24, -1,	4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1,	4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},	   24, -1,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},	   24, -1,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},	   24, -1,	4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1,	4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},	   18, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1,	1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1,	4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},	   23, -1,	4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},	   23, -1,	4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1247 typname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen			21 -1 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval			16 -1 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype			18 -1 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory		18 -1 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred	16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined		16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim			18 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid			26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem			26 -1 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray			26 -1 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput			24 -1 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput		24 -1 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive		24 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend			24 -1 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin			24 -1 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout		24 -1 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze		24 -1 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign			18 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage		18 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull		16 -1 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype		26 -1 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod		23 -1 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims			23 -1 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin	25 -1 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault		25 -1 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},			19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronamespace"},		26, -1, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},			26, -1, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},			26, -1, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},		   700, -1, 4,	5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorows"},		   700, -1, 4,	6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provariadic"},		26, -1, 4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},			16, -1, 1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},		16, -1, 1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},			16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},		16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},			16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},		18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},			21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},	21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},			26, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},		30, -1, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},	  1002, -1, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},	  1009, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},		25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"prosrc"},				25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"probin"},				17, -1, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proconfig"},		  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proacl"},			  1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1255 proname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang			26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost		   700 -1 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows		   700 -1 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic		26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg			16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow		16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef		16 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict		16 -1 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset		16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile		18 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs			21 -1 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults	21 -1 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype		26 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes		30 -1 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes	  1002 -1 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames	  1009 -1 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults	25 -1 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc			25 -1 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin			17 -1 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig	  1009 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl		  1034 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},	  26, -1,	4,	1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},	  19, -1, NAMEDATALEN,	2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypid"},	  26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},		  21, -1,	2,	5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},		  21, -1,	2,	6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},	  23, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},	  23, -1,	4,	9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},	  16, -1,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1,	1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},	  18, -1,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},	  16, -1,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1,	1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1,  -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1249 attrelid			26 -1  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname			19 -1 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid			26 -1  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget	23 -1  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen			21 -1  2   5 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum			21 -1  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims			23 -1  4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff		23 -1  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod		23 -1  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval			16 -1  1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage		18 -1  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign			18 -1  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull		16 -1  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef		16 -1  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped		16 -1  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal		16 -1  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount		23 -1  4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl		  1034 -1 -1  18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},	   26, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},		   26, -1,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},	   23, -1,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},	   700, -1, 4,	9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastrelid"}, 26, -1,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relistemp"},     16, -1,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},	   18, -1,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},	   21, -1,	2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},	   21, -1,	2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1,	1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1,	1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1,	4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},		 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner			26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam			26 -1 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode		26 -1 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace	26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages			23 -1 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples	   700 -1 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid	26 -1 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid	26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex		16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared		16 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relistemp		16 -1 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind			18 -1 1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts			21 -1 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks		21 -1 2  17 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids		16 -1 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey		16 -1 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules		16 -1 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers	16 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass	16 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid		28 -1 4  23 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl		  1034 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_index
--- 222,471 ----
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},	   19, -1, 0, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnamespace"},  26, -1, 0,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},	   26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},		   21, -1, 0,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},	   16, -1, 0,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},	   18, -1, 0,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1, 0,	1,	7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1, 0,	1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1, 0,	1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},	   18, -1, 0,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},	   26, -1, 0,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},	   26, -1, 0,	4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},	   26, -1, 0,	4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},	   24, -1, 0,	4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},	   24, -1, 0,	4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1, 0,	4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},	   24, -1, 0,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},	   24, -1, 0,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},	   24, -1, 0,	4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1, 0,	4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},	   18, -1, 0,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1, 0,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1, 0,	1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1, 0,	4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},	   23, -1, 0,	4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},	   23, -1, 0,	4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, 0, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, 0, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1247 typname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen			21 -1 0 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval			16 -1 0 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype			18 -1 0 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory		18 -1 0 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred	16 -1 0 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined		16 -1 0 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim			18 -1 0 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid			26 -1 0 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem			26 -1 0 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray			26 -1 0 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput			24 -1 0 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput		24 -1 0 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive		24 -1 0 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend			24 -1 0 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin			24 -1 0 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout		24 -1 0 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze		24 -1 0 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign			18 -1 0 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage		18 -1 0 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull		16 -1 0 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype		26 -1 0 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod		23 -1 0 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims			23 -1 0 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin	25 -1 0 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault		25 -1 0 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},			19, -1, 0, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronamespace"},		26, -1, 0, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},			26, -1, 0, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},			26, -1, 0, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},		   700, -1, 0, 4,	5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorows"},		   700, -1, 0, 4,	6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provariadic"},		26, -1, 0, 4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},			16, -1, 0, 1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},		16, -1, 0, 1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},			16, -1, 0, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},		16, -1, 0, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},			16, -1, 0, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},		18, -1, 0, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},			21, -1, 0, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},	21, -1, 0, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},			26, -1, 0, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},		30, -1, 0, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, 0, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},	  1002, -1, 0, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},	  1009, -1, 0, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},		25, -1, 0, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"prosrc"},				25, -1, 0, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"probin"},				17, -1, 0, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proconfig"},		  1009, -1, 0, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proacl"},			  1034, -1, 0, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1255 proname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang			26 -1 0 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost		   700 -1 0 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows		   700 -1 0 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic		26 -1 0 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg			16 -1 0 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow		16 -1 0 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef		16 -1 0 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict		16 -1 0 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset		16 -1 0 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile		18 -1 0 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs			21 -1 0 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults	21 -1 0 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype		26 -1 0 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes		30 -1 0 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 0 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes	  1002 -1 0 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames	  1009 -1 0 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults	25 -1 0 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc			25 -1 0 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin			17 -1 0 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig	  1009 -1 0 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl		  1034 -1 0 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},	  26, -1, 0,	4,	1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},	  19, -1, 0, NAMEDATALEN,	2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypid"},	  26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1, 0,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attdistinct"},  700, -1, 0,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},		  21, -1, 0,	2,	6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},		  21, -1, 0,	2,	7, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},	  23, -1, 0,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1, 0,	4,	9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},	  23, -1, 0,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},	  16, -1, 0,	1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1, 0,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},	  18, -1, 0,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1, 0,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},	  16, -1, 0,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1, 0,	1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1, 0,	1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1, 0,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1, 0,  -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1249 attrelid			26 -1 0  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname			19 -1 0 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid			26 -1 0  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget	23 -1 0  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attdistinct	   700 -1 0  4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen			21 -1 0  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum			21 -1 0  2   7 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims			23 -1 0  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff		23 -1 0  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod		23 -1 0  4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval			16 -1 0  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage		18 -1 0  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign			18 -1 0  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull		16 -1 0  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef		16 -1 0  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped		16 -1 0  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal		16 -1 0  1  17 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount		23 -1 0  4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl		  1034 -1 0 -1  19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},	   19, -1, 0, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnamespace"},  26, -1, 0,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},	   26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},	   26, -1, 0,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},		   26, -1, 0,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1, 0,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1, 0,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},	   23, -1, 0,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},	   700, -1, 0, 4,	9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastrelid"}, 26, -1, 0,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1, 0,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1, 0,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1, 0,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relistemp"},     16, -1, 0,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},	   18, -1, 0,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},	   21, -1, 0,	2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},	   21, -1, 0,	2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1, 0,	1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1, 0,	1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1, 0,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1, 0,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1, 0,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1, 0,	4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},		 1034, -1, 0, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, 0, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1259 relname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner			26 -1 0 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam			26 -1 0 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode		26 -1 0 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace	26 -1 0 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages			23 -1 0 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples	   700 -1 0 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid	26 -1 0 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid	26 -1 0 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex		16 -1 0 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared		16 -1 0 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relistemp		16 -1 0 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind			18 -1 0 1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts			21 -1 0 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks		21 -1 0 2  17 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids		16 -1 0 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey		16 -1 0 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules		16 -1 0 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers	16 -1 0 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass	16 -1 0 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid		28 -1 0 4  23 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl		  1034 -1 0 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions	  1009 -1 0 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_index
***************
*** 464,482 **** DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},		26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},			26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},			21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},		16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},		16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},	16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},		16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},		16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},		16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},			22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},			30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},			22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},			25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  #endif   /* PG_ATTRIBUTE_H */
--- 476,494 ----
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},		26, -1, 0, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},			26, -1, 0, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},			21, -1, 0, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},		16, -1, 0, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},		16, -1, 0, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},	16, -1, 0, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},		16, -1, 0, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},		16, -1, 0, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},		16, -1, 0, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},			22, -1, 0, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},			30, -1, 0, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},			22, -1, 0, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},			25, -1, 0, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},			25, -1, 0, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  #endif   /* PG_ATTRIBUTE_H */
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
***************
*** 125,131 **** typedef FormData_pg_class *Form_pg_class;
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 18 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
--- 125,131 ----
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 19 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1097,1104 **** typedef enum AlterTableType
  	AT_ColumnDefault,			/* alter column default */
  	AT_DropNotNull,				/* alter column drop not null */
  	AT_SetNotNull,				/* alter column set not null */
! 	AT_SetStatistics,			/* alter column statistics */
! 	AT_SetStorage,				/* alter column storage */
  	AT_DropColumn,				/* drop column */
  	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
  	AT_AddIndex,				/* add index */
--- 1097,1105 ----
  	AT_ColumnDefault,			/* alter column default */
  	AT_DropNotNull,				/* alter column drop not null */
  	AT_SetNotNull,				/* alter column set not null */
! 	AT_SetStatistics,			/* alter column set statistics */
! 	AT_SetDistinct,				/* alter column set distinct */
! 	AT_SetStorage,				/* alter column set storage */
  	AT_DropColumn,				/* drop column */
  	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
  	AT_AddIndex,				/* add index */
#22Jaime Casanova
jcasanov@systemguards.com.ec
In reply to: Robert Haas (#21)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, May 3, 2009 at 3:13 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Apr 6, 2009 at 11:15 AM, Robert Haas <robertmhaas@gmail.com> wrote:

So based on this comment and Stephen's remarks, I'm going to assume
that I'm succumbing to a fit of unjustified paranoia and re-implement
as you suggest.

OK, new version of patch, this time with the weird scaling removed and
the datatype changed to float4.

In this paragraph i think you mean: "ALTER TABLE ... ALTER COLUMN ...
SET DISTINCT"?

    <para>
+    The analyzer also estimates the number of distinct values that appear
+    in each column.  Because only a subset of pages are scanned, this method
+    can sometimes be quite inaccurate, especially for large tables.  If this
+    inaccuracy leads to bad query plans, the analyzer can be forced to use
+    a more correct value with <command>ALTER TABLE ... ALTER COLUMN ... SET
+    STATISTICS</command> (see <xref linkend="sql-altertable"
+    endterm="sql-altertable-title">).
+   </para>

--
Atentamente,
Jaime Casanova
Soporte y capacitación de PostgreSQL
Asesoría y desarrollo de sistemas
Guayaquil - Ecuador
Cel. +59387171157

#23Robert Haas
robertmhaas@gmail.com
In reply to: Jaime Casanova (#22)
1 attachment(s)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, May 3, 2009 at 11:14 PM, Jaime Casanova
<jcasanov@systemguards.com.ec> wrote:

On Sun, May 3, 2009 at 3:13 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Apr 6, 2009 at 11:15 AM, Robert Haas <robertmhaas@gmail.com> wrote:

So based on this comment and Stephen's remarks, I'm going to assume
that I'm succumbing to a fit of unjustified paranoia and re-implement
as you suggest.

OK, new version of patch, this time with the weird scaling removed and
the datatype changed to float4.

In this paragraph i think you mean: "ALTER TABLE ... ALTER COLUMN ...
SET DISTINCT"?

Ah, yes, so I do. Corrected patch attached.

I have not changed the minimum value for remoteVersion in pg_dump.c,
as that would make the patch not able to be tested now. So that line
and the comment two lines following will need to be updated prior to
application. Also requires catversion bump.

...Robert

Attachments:

ndistinct-3.patchtext/x-diff; charset=US-ASCII; name=ndistinct-3.patchDownload
*** a/doc/src/sgml/ref/alter_table.sgml
--- b/doc/src/sgml/ref/alter_table.sgml
***************
*** 39,44 **** where <replaceable class="PARAMETER">action</replaceable> is one of:
--- 39,45 ----
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | DROP } NOT NULL
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
+     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DISTINCT<replaceable class="PARAMETER">floating point</replaceable>
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
      ADD <replaceable class="PARAMETER">table_constraint</replaceable>
      DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
***************
*** 154,159 **** where <replaceable class="PARAMETER">action</replaceable> is one of:
--- 155,186 ----
     </varlistentry>
  
     <varlistentry>
+     <term><literal>SET DISTINCT</literal></term>
+     <listitem>
+      <para>
+       This form can be used to override the result of the ndistinct computation
+       performed by subsequent
+       <xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
+       When set to a positive value, ANALYZE will assume that the column
+       contains exactly the specified number of distinct values (even if its
+       own analysis indicates otherwie).  When set to a negative value, which
+       must be greater than or equal to -1, it will assume that the
+       number of distinct values in the column is linear in the size of the
+       table, and will compute the exact value by multiplying the estimated
+       table size by the absolute value of the number specified.  This can
+       be useful when the size of the table changes over time; the
+       multiplication by the number of rows in the table is not performed until
+       query planning time.
+       Use a value of 0 to revert to computing the number of distinct values
+       normally.
+       For more information on the use of statistics by the
+       <productname>PostgreSQL</productname> query planner, refer to
+       <xref linkend="planner-stats">.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <indexterm>
       <primary>TOAST</primary>
       <secondary>per-column storage settings</secondary>
*** a/doc/src/sgml/ref/analyze.sgml
--- b/doc/src/sgml/ref/analyze.sgml
***************
*** 160,165 **** ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> [ ( <re
--- 160,175 ----
    </para>
  
    <para>
+    The analyzer also estimates the number of distinct values that appear
+    in each column.  Because only a subset of pages are scanned, this method
+    can sometimes be quite inaccurate, especially for large tables.  If this
+    inaccuracy leads to bad query plans, the analyzer can be forced to use
+    a more correct value with <command>ALTER TABLE ... ALTER COLUMN ... SET
+    DISTINCT</command> (see <xref linkend="sql-altertable"
+    endterm="sql-altertable-title">).
+   </para>
+ 
+   <para>
     The largest statistics target among the columns being analyzed determines
     the number of table rows sampled to prepare the statistics.  Increasing
     the target causes a proportional increase in the time and space needed
*** a/src/backend/access/common/tupdesc.c
--- b/src/backend/access/common/tupdesc.c
***************
*** 338,343 **** equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
--- 338,345 ----
  			return false;
  		if (attr1->attstattarget != attr2->attstattarget)
  			return false;
+ 		if (attr1->attdistinct != attr2->attdistinct)
+ 			return false;
  		if (attr1->attlen != attr2->attlen)
  			return false;
  		if (attr1->attndims != attr2->attndims)
***************
*** 465,470 **** TupleDescInitEntry(TupleDesc desc,
--- 467,473 ----
  		MemSet(NameStr(att->attname), 0, NAMEDATALEN);
  
  	att->attstattarget = -1;
+ 	att->attdistinct = 0;
  	att->attcacheoff = -1;
  	att->atttypmod = typmod;
  
*** a/src/backend/bootstrap/bootstrap.c
--- b/src/backend/bootstrap/bootstrap.c
***************
*** 743,748 **** DefineAttr(char *name, char *type, int attnum)
--- 743,749 ----
  	}
  
  	attrtypes[attnum]->attstattarget = -1;
+ 	attrtypes[attnum]->attdistinct = 0;
  	attrtypes[attnum]->attcacheoff = -1;
  	attrtypes[attnum]->atttypmod = -1;
  	attrtypes[attnum]->attislocal = true;
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 111,147 **** static List *insert_ordered_unique_oid(List *list, Oid datum);
   */
  
  static FormData_pg_attribute a1 = {
! 	0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
  	SelfItemPointerAttributeNumber, 0, -1, -1,
  	false, 'p', 's', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a2 = {
! 	0, {"oid"}, OIDOID, 0, sizeof(Oid),
  	ObjectIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a3 = {
! 	0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
  	MinTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a4 = {
! 	0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
  	MinCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a5 = {
! 	0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
  	MaxTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a6 = {
! 	0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
  	MaxCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
--- 111,147 ----
   */
  
  static FormData_pg_attribute a1 = {
! 	0, {"ctid"}, TIDOID, 0, 0, sizeof(ItemPointerData),
  	SelfItemPointerAttributeNumber, 0, -1, -1,
  	false, 'p', 's', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a2 = {
! 	0, {"oid"}, OIDOID, 0, 0, sizeof(Oid),
  	ObjectIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a3 = {
! 	0, {"xmin"}, XIDOID, 0, 0, sizeof(TransactionId),
  	MinTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a4 = {
! 	0, {"cmin"}, CIDOID, 0, 0, sizeof(CommandId),
  	MinCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a5 = {
! 	0, {"xmax"}, XIDOID, 0, 0, sizeof(TransactionId),
  	MaxTransactionIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
  
  static FormData_pg_attribute a6 = {
! 	0, {"cmax"}, CIDOID, 0, 0, sizeof(CommandId),
  	MaxCommandIdAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
***************
*** 153,159 **** static FormData_pg_attribute a6 = {
   * 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, { 0 }
  };
--- 153,159 ----
   * used in SQL.
   */
  static FormData_pg_attribute a7 = {
! 	0, {"tableoid"}, OIDOID, 0, 0, sizeof(Oid),
  	TableOidAttributeNumber, 0, -1, -1,
  	true, 'p', 'i', true, false, false, true, 0, { 0 }
  };
***************
*** 514,519 **** InsertPgAttributeTuple(Relation pg_attribute_rel,
--- 514,520 ----
  	values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
  	values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
  	values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
+ 	values[Anum_pg_attribute_attdistinct - 1] = Float8GetDatum(new_attribute->attdistinct);
  
  	/* start out with empty permissions */
  	nulls[Anum_pg_attribute_attacl - 1] = true;
***************
*** 570,575 **** AddNewAttributeTuples(Oid new_rel_oid,
--- 571,577 ----
  		attr->attrelid = new_rel_oid;
  		/* Make sure these are OK, too */
  		attr->attstattarget = -1;
+ 		attr->attdistinct = 0;
  		attr->attcacheoff = -1;
  
  		InsertPgAttributeTuple(rel, attr, indstate);
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 187,192 **** ConstructTupleDescriptor(Relation heapRelation,
--- 187,193 ----
  			to->attnum = i + 1;
  
  			to->attstattarget = -1;
+ 			to->attdistinct = 0;
  			to->attcacheoff = -1;
  			to->attnotnull = false;
  			to->atthasdef = false;
*** a/src/backend/commands/analyze.c
--- b/src/backend/commands/analyze.c
***************
*** 434,439 **** analyze_rel(Oid relid, VacuumStmt *vacstmt,
--- 434,448 ----
  									 std_fetch_func,
  									 numrows,
  									 totalrows);
+ 
+ 			/*
+ 			 * If the user has overridden the result of our stadistinct
+ 			 * calculation using ALTER TABLE ... ALTER COLUMN ... SET DISTINCT,
+ 			 * fill in the override value now.
+ 			 */
+ 			if (stats->attr->attdistinct != 0)
+ 				stats->stadistinct = stats->attr->attdistinct;
+ 
  			MemoryContextResetAndDeleteChildren(col_context);
  		}
  
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 283,288 **** static void ATPrepSetStatistics(Relation rel, const char *colName,
--- 283,290 ----
  					Node *flagValue);
  static void ATExecSetStatistics(Relation rel, const char *colName,
  					Node *newValue);
+ static void ATExecSetDistinct(Relation rel, const char *colName,
+ 				 Node *newValue);
  static void ATExecSetStorage(Relation rel, const char *colName,
  				 Node *newValue);
  static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
***************
*** 2401,2406 **** ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
--- 2403,2414 ----
  			ATPrepSetStatistics(rel, cmd->name, cmd->def);
  			pass = AT_PASS_COL_ATTRS;
  			break;
+ 		case AT_SetDistinct:	/* ALTER COLUMN STATISTICS */
+ 			ATSimplePermissions(rel, false);
+ 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
+ 			/* No command-specific prep needed */
+ 			pass = AT_PASS_COL_ATTRS;
+ 			break;
  		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATSimplePermissions(rel, false);
  			ATSimpleRecursion(wqueue, rel, cmd, recurse);
***************
*** 2610,2619 **** ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
  		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATExecSetNotNull(tab, rel, cmd->name);
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN STATISTICS */
  			ATExecSetStatistics(rel, cmd->name, cmd->def);
  			break;
! 		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATExecSetStorage(rel, cmd->name, cmd->def);
  			break;
  		case AT_DropColumn:		/* DROP COLUMN */
--- 2618,2630 ----
  		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATExecSetNotNull(tab, rel, cmd->name);
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN SET STATISTICS */
  			ATExecSetStatistics(rel, cmd->name, cmd->def);
  			break;
! 		case AT_SetDistinct:	/* ALTER COLUMN SET DISTINCT */
! 			ATExecSetDistinct(rel, cmd->name, cmd->def);
! 			break;
! 		case AT_SetStorage:		/* ALTER COLUMN SET STORAGE */
  			ATExecSetStorage(rel, cmd->name, cmd->def);
  			break;
  		case AT_DropColumn:		/* DROP COLUMN */
***************
*** 4075,4080 **** ATExecSetStatistics(Relation rel, const char *colName, Node *newValue)
--- 4086,4157 ----
  }
  
  /*
+  * ALTER TABLE ALTER COLUMN SET DISTINCT
+  */
+ static void
+ ATExecSetDistinct(Relation rel, const char *colName, Node *newValue)
+ {
+ 	float4		newdistinct;
+ 	Relation	attrelation;
+ 	HeapTuple	tuple;
+ 	Form_pg_attribute attrtuple;
+ 
+ 	switch (nodeTag(newValue))
+ 	{
+ 		case T_Integer:
+ 			newdistinct = intVal(newValue);
+ 			break;
+ 		case T_Float:
+ 			newdistinct = floatVal(newValue);
+ 			break;
+ 		default:
+ 			elog(ERROR, "unrecognized node type: %d",
+ 				 (int) nodeTag(newValue));
+ 			/* keep compiler quiet */
+ 			newdistinct = 0;
+ 	}
+ 
+ 	/*
+ 	 * Limit target to a sane range
+ 	 */
+ 	if (newdistinct < -1.0)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				 errmsg("number of distinct values %f is too low",
+ 						newdistinct)));
+ 	}
+ 
+ 	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
+ 
+ 	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_COLUMN),
+ 				 errmsg("column \"%s\" of relation \"%s\" does not exist",
+ 						colName, RelationGetRelationName(rel))));
+ 	attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
+ 
+ 	if (attrtuple->attnum <= 0)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot alter system column \"%s\"",
+ 						colName)));
+ 
+ 	attrtuple->attdistinct = newdistinct;
+ 
+ 	simple_heap_update(attrelation, &tuple->t_self, tuple);
+ 
+ 	/* keep system catalog indexes current */
+ 	CatalogUpdateIndexes(attrelation, tuple);
+ 
+ 	heap_freetuple(tuple);
+ 
+ 	heap_close(attrelation, RowExclusiveLock);
+ }
+ 
+ /*
   * ALTER TABLE ALTER COLUMN SET STORAGE
   */
  static void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 1584,1589 **** alter_table_cmd:
--- 1584,1598 ----
  					n->def = (Node *) makeInteger($6);
  					$$ = (Node *)n;
  				}
+ 			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET DISTINCT <SignedIconst> */
+ 			| ALTER opt_column ColId SET DISTINCT NumericOnly
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_SetDistinct;
+ 					n->name = $3;
+ 					n->def = (Node *) $6;
+ 					$$ = (Node *)n;
+ 				}
  			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
  			| ALTER opt_column ColId SET STORAGE ColId
  				{
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 4637,4642 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4637,4643 ----
  	int			i_atttypname;
  	int			i_atttypmod;
  	int			i_attstattarget;
+ 	int			i_attdistinct;
  	int			i_attstorage;
  	int			i_typstorage;
  	int			i_attnotnull;
***************
*** 4682,4688 **** getTableAttrs(TableInfo *tblinfo, int numTables)
  
  		resetPQExpBuffer(q);
  
! 		if (g_fout->remoteVersion >= 70300)
  		{
  			/* need left join here to not fail on dropped columns ... */
  			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
--- 4683,4705 ----
  
  		resetPQExpBuffer(q);
  
! 		if (g_fout->remoteVersion >= 80400)
! 		{
! 			/* attdistinct doesn't exist prior to 8.4 */
! 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
! 								 "a.attstattarget, a.attdistinct, "
! 								 "a.attstorage, t.typstorage, a.attnotnull, "
! 								 "a.atthasdef, a.attisdropped, a.attlen, "
! 								 "a.attalign, a.attislocal, "
! 				   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
! 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
! 							  "ON a.atttypid = t.oid "
! 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
! 							  "AND a.attnum > 0::pg_catalog.int2 "
! 							  "ORDER BY a.attrelid, a.attnum",
! 							  tbinfo->dobj.catId.oid);
! 		}
! 		else if (g_fout->remoteVersion >= 70300)
  		{
  			/* need left join here to not fail on dropped columns ... */
  			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
***************
*** 4744,4749 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4761,4767 ----
  		i_atttypname = PQfnumber(res, "atttypname");
  		i_atttypmod = PQfnumber(res, "atttypmod");
  		i_attstattarget = PQfnumber(res, "attstattarget");
+ 		i_attdistinct = PQfnumber(res, "attdistinct");
  		i_attstorage = PQfnumber(res, "attstorage");
  		i_typstorage = PQfnumber(res, "typstorage");
  		i_attnotnull = PQfnumber(res, "attnotnull");
***************
*** 4758,4763 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4776,4782 ----
  		tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
  		tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
  		tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
+ 		tbinfo->attdistinct = (char **) malloc(ntups * sizeof(char *));
  		tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
  		tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
  		tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
***************
*** 4783,4788 **** getTableAttrs(TableInfo *tblinfo, int numTables)
--- 4802,4808 ----
  			tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
  			tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
  			tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
+ 			tbinfo->attdistinct[j] = strdup(PQgetvalue(res, j, i_attdistinct));
  			tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
  			tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
  			tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
***************
*** 9938,9943 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
--- 9958,9979 ----
  			}
  
  			/*
+ 			 * Dump per-column distinct information. We only issue an ALTER
+ 			 * TABLE statement if the attdistinct entry for this column is
+ 			 * non-zero (i.e. it's not the default value)
+ 			 */
+ 			if (atof(tbinfo->attdistinct[j]) != 0 &&
+ 				!tbinfo->attisdropped[j])
+ 			{
+ 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
+ 								  fmtId(tbinfo->dobj.name));
+ 				appendPQExpBuffer(q, "ALTER COLUMN %s SET DISTINCT ",
+ 								  fmtId(tbinfo->attnames[j]));
+ 				appendStringLiteralAH(q, tbinfo->attdistinct[j], fout);
+ 				appendPQExpBuffer(q, ";\n");
+ 			}
+ 
+ 			/*
  			 * Dump per-column storage information.  The statement is only
  			 * dumped if the storage has been changed from the type's default.
  			 */
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
***************
*** 243,248 **** typedef struct _tableInfo
--- 243,249 ----
  	char	  **atttypnames;	/* attribute type names */
  	int		   *atttypmod;		/* type-specific type modifiers */
  	int		   *attstattarget;	/* attribute statistics targets */
+ 	char	  **attdistinct;	/* override ndistinct calculation */
  	char	   *attstorage;		/* attribute storage scheme */
  	char	   *typstorage;		/* type storage scheme */
  	bool	   *attisdropped;	/* true if attr is dropped; don't dump it */
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
***************
*** 970,976 **** psql_completion(char *text, int start, int end)
  		/* DROP ... does not work well yet */
  		static const char *const list_COLUMNALTER[] =
  		{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
! 		"DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
--- 970,977 ----
  		/* DROP ... does not work well yet */
  		static const char *const list_COLUMNALTER[] =
  		{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
! 		"DROP NOT NULL", "SET STATISTICS", "SET DISTINCT",
! 		"SET STORAGE", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
*** a/src/include/catalog/pg_attribute.h
--- b/src/include/catalog/pg_attribute.h
***************
*** 60,65 **** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS
--- 60,74 ----
  	int4		attstattarget;
  
  	/*
+ 	 * If this value is non-zero, it overrides the default ndistinct
+ 	 * computation performed by ANALYZE.  If attdistinct is positive, it
+ 	 * specifies the exact number of distinct values assumed to be present in
+ 	 * this column.  If negative, the number of distinct values is assumed to
+ 	 * be attdistinct * -1.0 * (# of rows in table).
+ 	 */
+ 	float4		attdistinct;
+ 
+ 	/*
  	 * attlen is a copy of the typlen field from pg_type for this attribute.
  	 * See atttypid comments above.
  	 */
***************
*** 176,200 **** typedef FormData_pg_attribute *Form_pg_attribute;
   * ----------------
   */
  
! #define Natts_pg_attribute				18
  #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_attacl		18
  
  
  /* ----------------
--- 185,210 ----
   * ----------------
   */
  
! #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_attstattarget 4
! #define Anum_pg_attribute_attdistinct	5
! #define Anum_pg_attribute_attlen		6
! #define Anum_pg_attribute_attnum		7
! #define Anum_pg_attribute_attndims		8
! #define Anum_pg_attribute_attcacheoff	9
! #define Anum_pg_attribute_atttypmod		10
! #define Anum_pg_attribute_attbyval		11
! #define Anum_pg_attribute_attstorage	12
! #define Anum_pg_attribute_attalign		13
! #define Anum_pg_attribute_attnotnull	14
! #define Anum_pg_attribute_atthasdef		15
! #define Anum_pg_attribute_attisdropped	16
! #define Anum_pg_attribute_attislocal	17
! #define Anum_pg_attribute_attinhcount	18
! #define Anum_pg_attribute_attacl		19
  
  
  /* ----------------
***************
*** 212,459 **** typedef FormData_pg_attribute *Form_pg_attribute;
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},		   21, -1,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},	   16, -1,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},	   18, -1,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1,	1,	7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1,	1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1,	1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},	   18, -1,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},	   26, -1,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},	   26, -1,	4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},	   26, -1,	4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},	   24, -1,	4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},	   24, -1,	4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1,	4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},	   24, -1,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},	   24, -1,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},	   24, -1,	4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1,	4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},	   18, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1,	1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1,	4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},	   23, -1,	4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},	   23, -1,	4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1247 typname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen			21 -1 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval			16 -1 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype			18 -1 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory		18 -1 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred	16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined		16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim			18 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid			26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem			26 -1 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray			26 -1 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput			24 -1 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput		24 -1 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive		24 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend			24 -1 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin			24 -1 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout		24 -1 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze		24 -1 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign			18 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage		18 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull		16 -1 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype		26 -1 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod		23 -1 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims			23 -1 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin	25 -1 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault		25 -1 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},			19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronamespace"},		26, -1, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},			26, -1, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},			26, -1, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},		   700, -1, 4,	5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorows"},		   700, -1, 4,	6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provariadic"},		26, -1, 4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},			16, -1, 1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},		16, -1, 1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},			16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},		16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},			16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},		18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},			21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},	21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},			26, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},		30, -1, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},	  1002, -1, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},	  1009, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},		25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"prosrc"},				25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"probin"},				17, -1, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proconfig"},		  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proacl"},			  1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1255 proname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang			26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost		   700 -1 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows		   700 -1 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic		26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg			16 -1 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow		16 -1 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef		16 -1 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict		16 -1 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset		16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile		18 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs			21 -1 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults	21 -1 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype		26 -1 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes		30 -1 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes	  1002 -1 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames	  1009 -1 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults	25 -1 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc			25 -1 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin			17 -1 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig	  1009 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl		  1034 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},	  26, -1,	4,	1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},	  19, -1, NAMEDATALEN,	2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypid"},	  26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},		  21, -1,	2,	5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},		  21, -1,	2,	6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},	  23, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},	  23, -1,	4,	9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},	  16, -1,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1,	1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},	  18, -1,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},	  16, -1,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1,	1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1,  -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1249 attrelid			26 -1  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname			19 -1 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid			26 -1  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget	23 -1  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen			21 -1  2   5 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum			21 -1  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims			23 -1  4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff		23 -1  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod		23 -1  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval			16 -1  1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage		18 -1  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign			18 -1  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull		16 -1  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef		16 -1  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped		16 -1  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal		16 -1  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount		23 -1  4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl		  1034 -1 -1  18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},	   26, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},		   26, -1,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},	   23, -1,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},	   700, -1, 4,	9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastrelid"}, 26, -1,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relistemp"},     16, -1,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},	   18, -1,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},	   21, -1,	2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},	   21, -1,	2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1,	1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1,	1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1,	4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},		 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype			26 -1 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner			26 -1 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam			26 -1 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode		26 -1 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace	26 -1 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages			23 -1 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples	   700 -1 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid	26 -1 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid	26 -1 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex		16 -1 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared		16 -1 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relistemp		16 -1 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind			18 -1 1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts			21 -1 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks		21 -1 2  17 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids		16 -1 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey		16 -1 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules		16 -1 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers	16 -1 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass	16 -1 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid		28 -1 4  23 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl		  1034 -1 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin				29 0  4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_index
--- 222,471 ----
   * ----------------
   */
  #define Schema_pg_type \
! { 1247, {"typname"},	   19, -1, 0, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnamespace"},  26, -1, 0,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typowner"},	   26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typlen"},		   21, -1, 0,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbyval"},	   16, -1, 0,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtype"},	   18, -1, 0,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typcategory"},   18, -1, 0,	1,	7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typispreferred"},16, -1, 0,	1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typisdefined"},  16, -1, 0,	1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdelim"},	   18, -1, 0,	1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typrelid"},	   26, -1, 0,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typelem"},	   26, -1, 0,	4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typarray"},	   26, -1, 0,	4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typinput"},	   24, -1, 0,	4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typoutput"},	   24, -1, 0,	4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typreceive"},    24, -1, 0,	4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typsend"},	   24, -1, 0,	4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodin"},	   24, -1, 0,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typmodout"},	   24, -1, 0,	4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typanalyze"},    24, -1, 0,	4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typalign"},	   18, -1, 0,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typstorage"},    18, -1, 0,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typnotnull"},    16, -1, 0,	1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typbasetype"},   26, -1, 0,	4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typtypmod"},	   23, -1, 0,	4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typndims"},	   23, -1, 0,	4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefaultbin"}, 25, -1, 0, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1247, {"typdefault"},    25, -1, 0, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1247 typname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1247 typnamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typowner			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typlen			21 -1 0 2   4 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1247 typbyval			16 -1 0 1   5 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typtype			18 -1 0 1   6 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typcategory		18 -1 0 1   7 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typispreferred	16 -1 0 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typisdefined		16 -1 0 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typdelim			18 -1 0 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typrelid			26 -1 0 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typelem			26 -1 0 4  12 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typarray			26 -1 0 4  13 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typinput			24 -1 0 4  14 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typoutput		24 -1 0 4  15 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typreceive		24 -1 0 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typsend			24 -1 0 4  17 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodin			24 -1 0 4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typmodout		24 -1 0 4  19 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typanalyze		24 -1 0 4  20 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typalign			18 -1 0 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typstorage		18 -1 0 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typnotnull		16 -1 0 1  23 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1247 typbasetype		26 -1 0 4  24 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typtypmod		23 -1 0 4  25 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typndims			23 -1 0 4  26 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 typdefaultbin	25 -1 0 -1 27 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 typdefault		25 -1 0 -1 28 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1247 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1247 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1247 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_proc
   * ----------------
   */
  #define Schema_pg_proc \
! { 1255, {"proname"},			19, -1, 0, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronamespace"},		26, -1, 0, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proowner"},			26, -1, 0, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prolang"},			26, -1, 0, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"procost"},		   700, -1, 0, 4,	5, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorows"},		   700, -1, 0, 4,	6, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provariadic"},		26, -1, 0, 4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisagg"},			16, -1, 0, 1,	8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proiswindow"},		16, -1, 0, 1,	9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prosecdef"},			16, -1, 0, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proisstrict"},		16, -1, 0, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proretset"},			16, -1, 0, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"provolatile"},		18, -1, 0, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargs"},			21, -1, 0, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"pronargdefaults"},	21, -1, 0, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1255, {"prorettype"},			26, -1, 0, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proargtypes"},		30, -1, 0, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1255, {"proallargtypes"},   1028, -1, 0, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargmodes"},	  1002, -1, 0, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargnames"},	  1009, -1, 0, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proargdefaults"},		25, -1, 0, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"prosrc"},				25, -1, 0, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"probin"},				17, -1, 0, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proconfig"},		  1009, -1, 0, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1255, {"proacl"},			  1034, -1, 0, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1255 proname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1255 pronamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proowner			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 prolang			26 -1 0 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 procost		   700 -1 0 4   5 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 prorows		   700 -1 0 4   6 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1255 provariadic		26 -1 0 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proisagg			16 -1 0 1   8 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proiswindow		16 -1 0 1   9 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 prosecdef		16 -1 0 1  10 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proisstrict		16 -1 0 1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 proretset		16 -1 0 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 provolatile		18 -1 0 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1255 pronargs			21 -1 0 2  14 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 pronargdefaults	21 -1 0 2  15 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1255 prorettype		26 -1 0 4  16 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 proargtypes		30 -1 0 -1 17 1 -1 -1 f p i t f f t 0 _null_));
! DATA(insert ( 1255 proallargtypes 1028 -1 0 -1 18 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargmodes	  1002 -1 0 -1 19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargnames	  1009 -1 0 -1 20 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proargdefaults	25 -1 0 -1 21 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 prosrc			25 -1 0 -1 22 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 probin			17 -1 0 -1 23 0 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proconfig	  1009 -1 0 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 proacl		  1034 -1 0 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1255 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1255 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1255 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_attribute
   * ----------------
   */
  #define Schema_pg_attribute \
! { 1249, {"attrelid"},	  26, -1, 0,	4,	1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attname"},	  19, -1, 0, NAMEDATALEN,	2, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypid"},	  26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstattarget"}, 23, -1, 0,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attdistinct"},  700, -1, 0,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attlen"},		  21, -1, 0,	2,	6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnum"},		  21, -1, 0,	2,	7, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attndims"},	  23, -1, 0,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attcacheoff"},  23, -1, 0,	4,	9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atttypmod"},	  23, -1, 0,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attbyval"},	  16, -1, 0,	1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attstorage"},   18, -1, 0,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attalign"},	  18, -1, 0,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attnotnull"},   16, -1, 0,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"atthasdef"},	  16, -1, 0,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attisdropped"}, 16, -1, 0,	1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attislocal"},   16, -1, 0,	1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attinhcount"},  23, -1, 0,	4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1249, {"attacl"},     1034, -1, 0,  -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1249 attrelid			26 -1 0  4   1 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attname			19 -1 0 NAMEDATALEN  2 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1249 atttypid			26 -1 0  4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attstattarget	23 -1 0  4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attdistinct	   700 -1 0  4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attlen			21 -1 0  2   6 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attnum			21 -1 0  2   7 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1249 attndims			23 -1 0  4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attcacheoff		23 -1 0  4   9 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 atttypmod		23 -1 0  4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attbyval			16 -1 0  1  11 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attstorage		18 -1 0  1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attalign			18 -1 0  1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attnotnull		16 -1 0  1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 atthasdef		16 -1 0  1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attisdropped		16 -1 0  1  16 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attislocal		16 -1 0  1  17 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1249 attinhcount		23 -1 0  4  18 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 attacl		  1034 -1 0 -1  19 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1249 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
  /* no OIDs in pg_attribute */
! DATA(insert ( 1249 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1249 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_class
   * ----------------
   */
  #define Schema_pg_class \
! { 1259, {"relname"},	   19, -1, 0, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnamespace"},  26, -1, 0,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltype"},	   26, -1, 0,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relowner"},	   26, -1, 0,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relam"},		   26, -1, 0,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfilenode"},   26, -1, 0,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltablespace"}, 26, -1, 0,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relpages"},	   23, -1, 0,	4,	8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltuples"},	   700, -1, 0, 4,	9, 0, -1, -1, FLOAT4PASSBYVAL, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastrelid"}, 26, -1, 0,	4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"reltoastidxid"}, 26, -1, 0,	4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasindex"},   16, -1, 0,	1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relisshared"},   16, -1, 0,	1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relistemp"},     16, -1, 0,	1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relkind"},	   18, -1, 0,	1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relnatts"},	   21, -1, 0,	2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relchecks"},	   21, -1, 0,	2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasoids"},    16, -1, 0,	1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhaspkey"},    16, -1, 0,	1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhasrules"},   16, -1, 0,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhastriggers"},16, -1, 0,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relhassubclass"},16, -1, 0,	1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relfrozenxid"},  28, -1, 0,	4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 1259, {"relacl"},		 1034, -1, 0, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 1259, {"reloptions"},  1009, -1, 0, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
! 
! DATA(insert ( 1259 relname			19 -1 0 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0 _null_));
! DATA(insert ( 1259 relnamespace		26 -1 0 4   2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltype			26 -1 0 4   3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relowner			26 -1 0 4   4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relam			26 -1 0 4   5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relfilenode		26 -1 0 4   6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltablespace	26 -1 0 4   7 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relpages			23 -1 0 4   8 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltuples	   700 -1 0 4   9 0 -1 -1 FLOAT4PASSBYVAL p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastrelid	26 -1 0 4  10 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 reltoastidxid	26 -1 0 4  11 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relhasindex		16 -1 0 1  12 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relisshared		16 -1 0 1  13 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relistemp		16 -1 0 1  14 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relkind			18 -1 0 1  15 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relnatts			21 -1 0 2  16 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relchecks		21 -1 0 2  17 0 -1 -1 t p s t f f t 0 _null_));
! DATA(insert ( 1259 relhasoids		16 -1 0 1  18 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhaspkey		16 -1 0 1  19 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhasrules		16 -1 0 1  20 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhastriggers	16 -1 0 1  21 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relhassubclass	16 -1 0 1  22 0 -1 -1 t p c t f f t 0 _null_));
! DATA(insert ( 1259 relfrozenxid		28 -1 0 4  23 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 relacl		  1034 -1 0 -1 24 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 reloptions	  1009 -1 0 -1 25 1 -1 -1 f x i f f f t 0 _null_));
! DATA(insert ( 1259 ctid				27 0  0 6  -1 0 -1 -1 f p s t f f t 0 _null_));
! DATA(insert ( 1259 oid				26 0  0 4  -2 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmin				28 0  0 4  -3 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmin				29 0  0 4  -4 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 xmax				28 0  0 4  -5 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 cmax				29 0  0 4  -6 0 -1 -1 t p i t f f t 0 _null_));
! DATA(insert ( 1259 tableoid			26 0  0 4  -7 0 -1 -1 t p i t f f t 0 _null_));
  
  /* ----------------
   *		pg_index
***************
*** 464,482 **** DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},		26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},			26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},			21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},		16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},		16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},	16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},		16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},		16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},		16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},			22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},			30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},			22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},			25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  #endif   /* PG_ATTRIBUTE_H */
--- 476,494 ----
   * ----------------
   */
  #define Schema_pg_index \
! { 0, {"indexrelid"},		26, -1, 0, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indrelid"},			26, -1, 0, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indnatts"},			21, -1, 0, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisunique"},		16, -1, 0, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisprimary"},		16, -1, 0, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisclustered"},	16, -1, 0, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisvalid"},		16, -1, 0, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indcheckxmin"},		16, -1, 0, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indisready"},		16, -1, 0, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, { 0 } }, \
! { 0, {"indkey"},			22, -1, 0, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indclass"},			30, -1, 0, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indoption"},			22, -1, 0, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
! { 0, {"indexprs"},			25, -1, 0, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
! { 0, {"indpred"},			25, -1, 0, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
  
  #endif   /* PG_ATTRIBUTE_H */
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
***************
*** 125,131 **** typedef FormData_pg_class *Form_pg_class;
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 18 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
--- 125,131 ----
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
  DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 19 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
  DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1097,1104 **** typedef enum AlterTableType
  	AT_ColumnDefault,			/* alter column default */
  	AT_DropNotNull,				/* alter column drop not null */
  	AT_SetNotNull,				/* alter column set not null */
! 	AT_SetStatistics,			/* alter column statistics */
! 	AT_SetStorage,				/* alter column storage */
  	AT_DropColumn,				/* drop column */
  	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
  	AT_AddIndex,				/* add index */
--- 1097,1105 ----
  	AT_ColumnDefault,			/* alter column default */
  	AT_DropNotNull,				/* alter column drop not null */
  	AT_SetNotNull,				/* alter column set not null */
! 	AT_SetStatistics,			/* alter column set statistics */
! 	AT_SetDistinct,				/* alter column set distinct */
! 	AT_SetStorage,				/* alter column set storage */
  	AT_DropColumn,				/* drop column */
  	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
  	AT_AddIndex,				/* add index */
#24Joshua Tolley
eggyknap@gmail.com
In reply to: Robert Haas (#23)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Mon, May 04, 2009 at 10:13:31PM -0400, Robert Haas wrote:

<nit>

+ own analysis indicates otherwie). When set to a negative value, which

s/otherwie/otherwise
</nit>

A question: why does attdistinct become entry #5 instead of going at the end?
I assume it's because the order here controls the column order, and it makes
sense to have attdistinct next to attstattarget, since they're related. Is
that right? Thanks in advance...

--- 185,210 ----
* ----------------
*/

! #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_attstattarget 4
! #define Anum_pg_attribute_attdistinct 5
! #define Anum_pg_attribute_attlen 6
! #define Anum_pg_attribute_attnum 7

- Josh / eggyknap

#25Robert Haas
robertmhaas@gmail.com
In reply to: Joshua Tolley (#24)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Mon, May 4, 2009 at 10:41 PM, Joshua Tolley <eggyknap@gmail.com> wrote:

On Mon, May 04, 2009 at 10:13:31PM -0400, Robert Haas wrote:

<nit>

+       own analysis indicates otherwie).  When set to a negative value, which

s/otherwie/otherwise
</nit>

A question: why does attdistinct become entry #5 instead of going at the end?
I assume it's because the order here controls the column order, and it makes
sense to have attdistinct next to attstattarget, since they're related. Is
that right? Thanks in advance...

Yep, that was my thought.

...Robert

#26Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#25)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

On Mon, May 4, 2009 at 10:41 PM, Joshua Tolley <eggyknap@gmail.com> wrote:

A question: why does attdistinct become entry #5 instead of going at the end?
I assume it's because the order here controls the column order, and it makes
sense to have attdistinct next to attstattarget, since they're related. Is
that right? Thanks in advance...

Yep, that was my thought.

We generally want fixed-size columns before variable-size ones, to ease
accessing them from C code. So it shouldn't go at the end in any case.
Beyond that it's mostly aesthetics, with maybe some thought for avoiding
unnecessary alignment padding.

regards, tom lane

#27Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#26)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Tue, May 5, 2009 at 12:13 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Mon, May 4, 2009 at 10:41 PM, Joshua Tolley <eggyknap@gmail.com> wrote:

A question: why does attdistinct become entry #5 instead of going at the end?
I assume it's because the order here controls the column order, and it makes
sense to have attdistinct next to attstattarget, since they're related. Is
that right? Thanks in advance...

Yep, that was my thought.

We generally want fixed-size columns before variable-size ones, to ease
accessing them from C code.  So it shouldn't go at the end in any case.
Beyond that it's mostly aesthetics, with maybe some thought for avoiding
unnecessary alignment padding.

I thought about that as well; it should be OK where it is, in that regard.

...Robert

#28Dimitri Fontaine
dfontaine@hi-media.com
In reply to: Robert Haas (#21)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Hi,

Le 3 mai 09 à 22:13, Robert Haas a écrit :

OK, new version of patch, this time with the weird scaling removed and
the datatype changed to float4.

You've been assigning me this patch review, so here it goes :)

I have not changed the minimum value for remoteVersion in pg_dump.c,
as that would make the patch not able to be tested now. So that line
and the comment two lines following will need to be updated prior to
application. Also requires catversion bump.

I guess now would be a good time to fix this part of the patch?

I couldn't apply it to current head because of bitrot. It applies fine
to git commit bcaef8b5a0e2d5c143dabd8516090a09e39b27b8 [1]http://git.postgresql.org/gitweb?p=postgresql.git;a=commit;h=bcaef8b5a0e2d5c143dabd8516090a09e39b27b8 but from
there the automatic forward merge of git isn't able to merge
pg_attribute.h. As I don't have as much time to give to the review as
I'd like, I'd very much welcome if you could fix this part of your
patch and I'll resume my work thereafter.
I'll change the patch status to "Waiting on Author" as soon as I'll
have this mail id.

Now I've had time to read the code, here are my raw notes:

pg_dump.c:
             tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j,  
i_attstattarget));
+           tbinfo->attdistinct[j] = strdup(PQgetvalue(res, j,  
i_attdistinct));
...
+           if (atof(tbinfo->attdistinct[j]) != 0 &&
+               !tbinfo->attisdropped[j])

- style issue, convert at PQgetvalue() time

- prefer strtod() over atof? Here's what my local man page has to
say about the case:

The atof() function has been deprecated by strtod() and should
not be used in
new code.

tablecmds.c:
+   switch (nodeTag(newValue))
+   {
+       case T_Integer:
...
+       case T_Float:
...
+ 		default:
+ 			elog(ERROR, "unrecognized node type: %d",
+ 				 (int) nodeTag(newValue));

What about adding the following before the switch, to do like
surrounding code?
Assert(IsA(newValue, Integer) || IsA(newValue, Float));

Given your revised version I'll try to play around with ndistinct
behavior and exercise dump and restore, etc, but for now I'll pause my
work.

I guess I'll have a second look at the code to check that it's all in
the spirit of surrounding code, which I didn't complete yet (wanted to
exercise my abilities to apply the patch from a past commit and
forward-merge from there).

Regards,
--
dim

[1]: http://git.postgresql.org/gitweb?p=postgresql.git;a=commit;h=bcaef8b5a0e2d5c143dabd8516090a09e39b27b8

#29marcin mank
marcin.mank@gmail.com
In reply to: Robert Haas (#1)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

ALTER COLUMN SET DISTINCT

feels like adding a unique constraint.

ALTER COLUMN SET STATISTICS DISTINCT ?
ALTER COLUMN SET STATISTICS NDISTINCT ?

Greetings
Marcin

#30Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#28)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Fri, Jul 17, 2009 at 11:10 AM, Dimitri Fontaine<dfontaine@hi-> I
couldn't apply it to current head because of bitrot. It applies fine
to

git commit bcaef8b5a0e2d5c143dabd8516090a09e39b27b8 [1] but

This is one of the things that I hate about the requirement to post
context diffs: filterdiff, at least for me, strips out the git tags
that indicate the base rev of the patch. In fact that rev is BEFORE
the one I based the patch on, which was
64b2da3f7778bc6fd3d213ceb9e73ff3b6e03890, and it actually applies OK
up until 0e3abe7ec78a3d51032d684598f188b0b0304fe9, the commit
immediately preceding the 8.4 pgindent run.

Now I've had time to read the code, here are my raw notes:

pg_dump.c:
           tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j,
i_attstattarget));
+           tbinfo->attdistinct[j] = strdup(PQgetvalue(res, j,
i_attdistinct));
...
+           if (atof(tbinfo->attdistinct[j]) != 0 &&
+               !tbinfo->attisdropped[j])

 - style issue, convert at PQgetvalue() time

Ah, good catch.

 - prefer strtod() over atof? Here's what my local man page has to say about
the case:

    The atof() function has been deprecated by strtod() and should not be
used in
    new code.

Hmm, I didn't know that (my man page doesn't contain that language).
It looks like strtod() is more widely used in the existing source code
than atof(), so I'll change it (atof() is however used in the
floatVal() macro).

tablecmds.c:
+   switch (nodeTag(newValue))
+   {
+       case T_Integer:
...
+       case T_Float:
...
+               default:
+                       elog(ERROR, "unrecognized node type: %d",
+                                (int) nodeTag(newValue));

 What about adding the following before the switch, to do like surrounding
code?
       Assert(IsA(newValue, Integer) || IsA(newValue, Float));

Not a good plan. In my experience, gcc doesn't like switch ()
statements over enums that don't list all the values, unless they have
a default clause; it masterminds by giving you a warning that you've
"inadvertently" left out some values.

Given your revised version I'll try to play around with ndistinct behavior
and exercise dump and restore, etc, but for now I'll pause my work.

I guess I'll have a second look at the code to check that it's all in the
spirit of surrounding code, which I didn't complete yet (wanted to exercise
my abilities to apply the patch from a past commit and forward-merge from
there).

OK. My one concern about updating this is that Peter is currently
reviewing my patch to autogenerate headers & bki stuff. If that gets
committed it's going to break this all again, and I'd rather just fix
it once (especially since that patch would reduce the amount of fixing
needed here by 50%). Also if this gets applied after being fixed it
will break that one.

...Robert

#31Dimitri Fontaine
dfontaine@hi-media.com
In reply to: Robert Haas (#30)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Le 18 juil. 09 à 20:55, Robert Haas a écrit :

that indicate the base rev of the patch. In fact that rev is BEFORE
the one I based the patch on, which was
64b2da3f7778bc6fd3d213ceb9e73ff3b6e03890, and it actually applies OK
up until 0e3abe7ec78a3d51032d684598f188b0b0304fe9, the commit
immediately preceding the 8.4 pgindent run.

Robert told me on rrreviewers it's all whitespace stuff, which I could
confirmed after having trained my eyes to recognize the pattern and
mix and match whitespace and new column in the middle. Patch applied,
I'll have to update the version check, but the following paste means
I'm the one having to work on it now:

Table "pg_catalog.pg_attribute"
Column | Type | Modifiers
---------------+-----------+-----------
...
attstattarget | integer | not null
attdistinct | real | not null
attlen | smallint | not null

Hmm, I didn't know that (my man page doesn't contain that language).
It looks like strtod() is more widely used in the existing source code
than atof(), so I'll change it (atof() is however used in the
floatVal() macro).

Considering I don't have an updated version when I start again, I'll
have a try at it: don't rush into it yourself :)

What about adding the following before the switch, to do like
surrounding
code?
Assert(IsA(newValue, Integer) || IsA(newValue, Float));

Not a good plan. In my experience, gcc doesn't like switch ()
statements over enums that don't list all the values, unless they have
a default clause; it masterminds by giving you a warning that you've
"inadvertently" left out some values.

Maybe this could still be a supplementary barrier for cassert builds
in order to match existing code?
--
dim

I'm going to update the status of patch and resume work on it next week.

#32Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#31)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sat, Jul 18, 2009 at 5:54 PM, Dimitri Fontaine<dfontaine@hi-media.com> wrote:

I'm going to update the status of patch and resume work on it next week.

Any update?

...Robert

#33Dimitri Fontaine
dfontaine@hi-media.com
In reply to: Robert Haas (#32)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Le 29 juil. 09 à 13:07, Robert Haas a écrit :

On Sat, Jul 18, 2009 at 5:54 PM, Dimitri Fontaine<dfontaine@hi-media.com

wrote:
I'm going to update the status of patch and resume work on it next
week.

Any update?

Sorry about delays, resuming tomorrow evening is the current plan.
--
dim

#34Dimitri Fontaine
dfontaine@hi-media.com
In reply to: Robert Haas (#30)
1 attachment(s)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Hi,

Finally some update on the patch.

Le 18 juil. 09 à 20:55, Robert Haas a écrit :

This is one of the things that I hate about the requirement to post
context diffs: filterdiff, at least for me, strips out the git tags
that indicate the base rev of the patch.

Yes, and as I didn't have the time to install filterdiff I've attached
a revision of your patch in git format which adresses the problem I
mentioned, in a tarball also containing raw notes, tests, and
regression.{out,diffs}.

mqke check is failing on opr_sanity test in what looks like an
ordering issue, but I didn't feel confident enough to adapt the .out
to force the regression into passing.

- style issue, convert at PQgetvalue() time

Ah, good catch.

Fixed in the updated version, which uses a float4 variable in pg_dump
and strtod() rather than atof. This last point is maybe overkill as
I'm using:
tbinfo->attdistinct[j] = strtod(PQgetvalue(res, j, i_attdistinct),
(char **)NULL);

What about adding the following before the switch, to do like
surrounding
code?
Assert(IsA(newValue, Integer) || IsA(newValue, Float));

Not a good plan. In my experience, gcc doesn't like switch ()
statements over enums that don't list all the values, unless they have
a default clause; it masterminds by giving you a warning that you've
"inadvertently" left out some values.

I've left this part alone but still wonders about this, which is a new
user visible error message kind:
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(newValue));

Given your revised version I'll try to play around with ndistinct
behavior
and exercise dump and restore, etc, but for now I'll pause my work.

I failed to have 0 to allow for analyze to compute a value again, as
shown in the raw notes in attachement:

dim=# alter table foo alter column x set distinct 1;
ALTER TABLE
...
dim=# alter table foo alter column x set distinct 0;
ALTER TABLE
dim=# analyze verbose foo;
INFO: analyzing "public.foo"
INFO: "foo": scanned 4 of 4 pages, containing 1000 live rows and 0
dead rows; 1000 rows in sample, 1000 estimated total rows
ANALYZE
dim=# select attname, attdistinct from pg_attribute where attrelid =
'foo'::regclass and attname = 'x';
attname | attdistinct
---------+-------------
x | 0
(1 row)

What I understand from the doc part of your work contradicts what I
see here...

Regards,
--
dim

Will mark as Waiting on Author, as I need Robert to tell me what to do
next.

Attachments:

ndistinct.tgzapplication/octet-stream; name=ndistinct.tgz; x-unix-mode=0644Download
#35Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#34)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Fri, Jul 31, 2009 at 11:09 AM, Dimitri
Fontaine<dfontaine@hi-media.com> wrote:

I failed to have 0 to allow for analyze to compute a value again, as shown
in the raw notes in attachement:

I'm lost. I think you're getting the new column attdistinct mixed up
with the existing column stadistinct. attdistinct is always going to
have whatever value you assign it. stadistinct will get attdistinct
!= 0 ? attdistinct : <result of analyze calculation>.

...Robert

#36Dimitri Fontaine
dfontaine@hi-media.com
In reply to: Robert Haas (#35)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Hi,

Le 1 août 09 à 06:08, Robert Haas a écrit :

I'm lost. I think you're getting the new column attdistinct mixed up
with the existing column stadistinct. attdistinct is always going to
have whatever value you assign it. stadistinct will get attdistinct
!= 0 ? attdistinct : <result of analyze calculation>.

haha!
Sorry about that, I felt like I had to run against time and once again
I lost.

dim=# alter table foo alter column x set distinct 0.25;
ALTER TABLE
dim=# select stadistinct from pg_statistic where starelid =
'foo'::regclass;
-[ RECORD 1 ]-----
stadistinct | 0.25

dim=# alter table foo alter column x set distinct 0;
ALTER TABLE
dim=# analyze verbose foo;
INFO: analyzing "public.foo"
INFO: "foo": scanned 4 of 4 pages, containing 1000 live rows and 0
dead rows; 1000 rows in sample, 1000 estimated total rows
ANALYZE
dim=# select stadistinct from pg_statistic where starelid =
'foo'::regclass;
stadistinct
-------------
-0.652
(1 row)

I'm back on track, it seems. Time to further test this, but code
review is ok for me (except for the strange new error already
mentioned), doc is ok too, and basic behaviour is sane. I just checked
pg_dump dim|psql foo and new database (foo) has same explicit distinct
settings than origin, both for pg_attribute and pg_statistic.

Unless you want me to test for impact on planner choices (even if we
already know it has impact on pg_statistic), I'd say it's ready for
commiter.

--
dim

#37Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#36)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sat, Aug 1, 2009 at 7:27 AM, Dimitri Fontaine<dfontaine@hi-media.com> wrote:

Unless you want me to test for impact on planner choices (even if we already
know it has impact on pg_statistic), I'd say it's ready for commiter.

Great, thanks for the review. I think if stadistinct is getting
populated that's sufficient in terms of testing; the problems caused
by inaccurate ndistinct estimates have been discussed elsewhere. I
see you've already marked this Ready for Committer, thanks.

...Robert

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: marcin mank (#29)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

There wasn't any response to this comment:

marcin mank <marcin.mank@gmail.com> writes:

ALTER COLUMN SET DISTINCT
feels like adding a unique constraint.

ALTER COLUMN SET STATISTICS DISTINCT ?
ALTER COLUMN SET STATISTICS NDISTINCT ?

I don't want to add a new keyword, but "SET STATISTICS DISTINCT" would
be an easy change. Comments?

regards, tom lane

#39Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#38)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

2009/8/2 Tom Lane <tgl@sss.pgh.pa.us>:

There wasn't any response to this comment:

marcin mank <marcin.mank@gmail.com> writes:

ALTER COLUMN SET DISTINCT
feels like adding a unique constraint.

ALTER COLUMN SET STATISTICS DISTINCT ?
ALTER COLUMN SET STATISTICS NDISTINCT ?

I don't want to add a new keyword, but "SET STATISTICS DISTINCT" would
be an easy change.  Comments?

It's much better than SET DISTINCT.

Pavel

Show quoted text

                       regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#40Joshua Tolley
eggyknap@gmail.com
In reply to: Tom Lane (#38)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Aug 02, 2009 at 01:23:27PM -0400, Tom Lane wrote:

There wasn't any response to this comment:

marcin mank <marcin.mank@gmail.com> writes:

ALTER COLUMN SET DISTINCT
feels like adding a unique constraint.

ALTER COLUMN SET STATISTICS DISTINCT ?
ALTER COLUMN SET STATISTICS NDISTINCT ?

I don't want to add a new keyword, but "SET STATISTICS DISTINCT" would
be an easy change. Comments?

+1

--
Joshua Tolley / eggyknap
End Point Corporation
http://www.endpoint.com

#41Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dimitri Fontaine (#34)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Dimitri Fontaine <dfontaine@hi-media.com> writes:

Yes, and as I didn't have the time to install filterdiff I've attached
a revision of your patch in git format which adresses the problem I
mentioned, in a tarball also containing raw notes, tests, and
regression.{out,diffs}.

Applied with assorted corrections, plus the just-discussed change of
syntax to SET STATISTICS DISTINCT.

mqke check is failing on opr_sanity test in what looks like an
ordering issue, but I didn't feel confident enough to adapt the .out
to force the regression into passing.

Hmm, I saw no such change here, so I left the regression test alone.
It might be a platform-specific behavior, in which case the buildfarm
will soon tell us. If so, adding an ORDER BY to that query seems
like the right fix.

regards, tom lane

#42Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#41)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Aug 2, 2009 at 6:17 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

Dimitri Fontaine <dfontaine@hi-media.com> writes:

Yes, and as I didn't have the time to install filterdiff I've attached
a revision of your patch in git format which adresses the problem I
mentioned, in a tarball also containing raw notes, tests, and
regression.{out,diffs}.

Applied with assorted corrections, plus the just-discussed change of
syntax to SET STATISTICS DISTINCT.

Thanks. The changes all look good - except I'm curious why %g vs. %f?

...Robert

#43Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#42)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Robert Haas <robertmhaas@gmail.com> writes:

Thanks. The changes all look good - except I'm curious why %g vs. %f?

So as not to add ".000000" unnecessarily. Positive values for ndistinct
should be treated as integers. (I considered adding an error check to
reject values like 20.5, but refrained...)

regards, tom lane

#44Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#43)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

On Sun, Aug 2, 2009 at 8:35 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Thanks.  The changes all look good - except I'm curious why %g vs. %f?

So as not to add ".000000" unnecessarily.  Positive values for ndistinct
should be treated as integers.  (I considered adding an error check to
reject values like 20.5, but refrained...)

Oh, I see. That makes sense.

I think we do entirely too much forcing things to integers in the
query planner as it is. The fact that a value can't truly be
fractional doesn't mean that an estimate of the value can't be
fractional.

Now, in this particular case, it seems hard to imagine that 20.5 is a
very useful value. But that's not really our problem: we just need to
reject illegal values, not useless ones.

I'm interested to see how useful this proves to be in the field. I
implemented it mostly on a whim because you and others seemed to think
it could have some value, and because I get an unhealthy amount of
personal satisfaction out of writing code during my spare time. But
the real test will be to see whether the real users who were getting
bad query plans as a result of poor ndistinct estimates are able to
make practical use of this feature to get better ones.

...Robert

#45Kim Bisgaard
kim+pg@alleroedderne.adsl.dk
In reply to: Tom Lane (#41)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Are there plans to make a small follow-up patch to make
CREATE UNIQUE INDEX on one column
(and variants in CREATE TABLE ... PRIMARY KEY) automatically do
SET STATISTICS DISTINCT?

It might not be as perfect a solution as teaching the planner to know
about unique indexes, but it is better than nothing.

Good work!

Regards,
Kim

#46Tom Lane
tgl@sss.pgh.pa.us
In reply to: Kim Bisgaard (#45)
Re: ALTER TABLE ... ALTER COLUMN ... SET DISTINCT

Kim Bisgaard <kim+pg@alleroedderne.adsl.dk> writes:

Are there plans to make a small follow-up patch to make
CREATE UNIQUE INDEX on one column
(and variants in CREATE TABLE ... PRIMARY KEY) automatically do
SET STATISTICS DISTINCT?

No. It would be pointless for a single column and wrong for
multiple columns.

regards, tom lane