Index: doc/src/sgml/catalogs.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/catalogs.sgml,v retrieving revision 2.183 diff -c -r2.183 catalogs.sgml *** doc/src/sgml/catalogs.sgml 21 Nov 2008 19:31:58 -0000 2.183 --- doc/src/sgml/catalogs.sgml 4 Dec 2008 18:28:42 -0000 *************** *** 89,99 **** - pg_autovacuum - per-relation autovacuum configuration parameters - - - pg_cast casts (data type conversions) --- 89,94 ---- *************** *** 1231,1401 **** - - <structname>pg_autovacuum</structname> - - - pg_autovacuum - - - - autovacuum - table-specific configuration - - - - The catalog pg_autovacuum stores optional - per-relation configuration parameters for the autovacuum daemon. - If there is an entry here for a particular relation, the given - parameters will be used for autovacuuming that table. If no entry - is present, the system-wide defaults will be used. For more information - about the autovacuum daemon, see . - - - - - It is likely that pg_autovacuum will disappear - in a future release, with the information instead being kept in - pg_class.reloptions entries. - - - - - <structname>pg_autovacuum</> Columns - - - - - Name - Type - References - Description - - - - - - vacrelid - oid - pg_class.oid - The table this entry is for - - - - enabled - bool - - If false, this table will not be autovacuumed, except - to prevent transaction ID wraparound - - - - vac_base_thresh - integer - - Minimum number of modified tuples before vacuum - - - - vac_scale_factor - float4 - - Multiplier for reltuples to add to - vac_base_thresh - - - - anl_base_thresh - integer - - Minimum number of modified tuples before analyze - - - - anl_scale_factor - float4 - - Multiplier for reltuples to add to - anl_base_thresh - - - - vac_cost_delay - integer - - Custom vacuum_cost_delay parameter - - - - vac_cost_limit - integer - - Custom vacuum_cost_limit parameter - - - - freeze_min_age - integer - - Custom vacuum_freeze_min_age parameter - - - - freeze_max_age - integer - - Custom autovacuum_freeze_max_age parameter - - - -
- - - The autovacuum daemon will initiate a VACUUM operation - on a particular table when the number of updated or deleted tuples - exceeds vac_base_thresh plus - vac_scale_factor times the number of - live tuples currently estimated to be in the relation. - Similarly, it will initiate an ANALYZE operation - when the number of inserted, updated or deleted tuples - exceeds anl_base_thresh plus - anl_scale_factor times the number of - live tuples currently estimated to be in the relation. - - - - Also, the autovacuum daemon will perform a VACUUM operation - to prevent transaction ID wraparound if the table's - pg_class.relfrozenxid field attains an age - of more than freeze_max_age transactions, whether the table - has been changed or not, even if - pg_autovacuum.enabled is set to - false for it. The system will launch autovacuum to perform - such VACUUMs even if autovacuum is otherwise disabled. - See for more about wraparound - prevention. - - - - Any of the numerical fields can contain -1 (or indeed - any negative value) to indicate that the system-wide default should - be used for this particular value. Observe that the - vac_cost_delay variable inherits its default value from the - configuration parameter, - or from if the former is set to a - negative value. The same applies to vac_cost_limit. - Also, autovacuum will ignore attempts to set a per-table - freeze_max_age larger than the system-wide setting (it can - only be set smaller), and the freeze_min_age value will be - limited to half the system-wide setting. Note that while you - can set freeze_max_age very small, or even zero, this - is usually unwise since it will force frequent vacuuming. - - -
- - <structname>pg_cast</structname> --- 1226,1231 ---- *************** *** 1786,1792 **** text[] ! Access-method-specific options, as keyword=value strings --- 1616,1622 ---- text[] ! Relation-specific options, as keyword=value strings Index: doc/src/sgml/config.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/config.sgml,v retrieving revision 1.198 diff -c -r1.198 config.sgml *** doc/src/sgml/config.sgml 21 Nov 2008 20:21:59 -0000 1.198 --- doc/src/sgml/config.sgml 4 Dec 2008 16:50:08 -0000 *************** *** 3518,3524 **** This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_autovacuum. --- 3518,3524 ---- This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_class.reloptions. *************** *** 3536,3542 **** This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_autovacuum. --- 3536,3542 ---- This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_class.reloptions. *************** *** 3555,3561 **** This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_autovacuum. --- 3555,3561 ---- This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_class.reloptions. *************** *** 3574,3580 **** This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_autovacuum. --- 3574,3580 ---- This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_class.reloptions. *************** *** 3595,3601 **** The default is 200 million transactions. This parameter can only be set at server start, but the setting can be reduced for individual tables by entries in ! pg_autovacuum. For more information see . --- 3595,3601 ---- The default is 200 million transactions. This parameter can only be set at server start, but the setting can be reduced for individual tables by entries in ! pg_class.reloptions. For more information see . *************** *** 3616,3622 **** This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_autovacuum. --- 3616,3622 ---- This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_class.reloptions. *************** *** 3638,3644 **** This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_autovacuum. --- 3638,3644 ---- This parameter can only be set in the postgresql.conf file or on the server command line. This setting can be overridden for individual tables by entries in ! pg_class.reloptions. Index: doc/src/sgml/maintenance.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/maintenance.sgml,v retrieving revision 1.86 diff -c -r1.86 maintenance.sgml *** doc/src/sgml/maintenance.sgml 16 Jun 2008 03:13:14 -0000 1.86 --- doc/src/sgml/maintenance.sgml 4 Dec 2008 17:34:55 -0000 *************** *** 576,640 **** The default thresholds and scale factors are taken from postgresql.conf, but it is possible to override them ! on a table-by-table basis by making entries in the system catalog pg_autovacuum. ! If a pg_autovacuum row exists for a particular ! table, the settings it specifies are applied; otherwise the global ! settings are used. See for ! more details on the global settings. Besides the base threshold values and scale factors, there are five ! more parameters that can be set for each table in ! pg_autovacuum. ! The first, pg_autovacuum.enabled, can be set to false to instruct the autovacuum daemon to skip that particular table entirely. In this case autovacuum will only touch the table if it must do so to prevent transaction ID wraparound. The next two parameters, the vacuum cost delay ! (pg_autovacuum.vac_cost_delay) ! and the vacuum cost limit ! (pg_autovacuum.vac_cost_limit), ! are used to set table-specific values for the feature. ! The last two parameters, ! (pg_autovacuum.freeze_min_age) ! and ! (pg_autovacuum.freeze_max_age), ! are used to set table-specific values for ! and respectively. ! If any of the values in pg_autovacuum ! are set to a negative number, or if a row is not present at all in ! pg_autovacuum for any particular table, the ! corresponding values from postgresql.conf are used. ! There is not currently any support for making ! pg_autovacuum entries, except by doing ! manual INSERTs into the catalog. This feature will be ! improved in future releases, and it is likely that the catalog ! definition will change. - - - The contents of the pg_autovacuum system - catalog are currently not saved in database dumps created by the - tools pg_dump and pg_dumpall. If - you want to preserve them across a dump/reload cycle, make sure - you dump the catalog manually. - - - When multiple workers are running, the cost limit is balanced among all the running workers, so that the --- 576,630 ---- The default thresholds and scale factors are taken from postgresql.conf, but it is possible to override them ! on a table-by-table basis by specifying options in the system catalog column pg_class.reloptions. ! If there is options in pg_class.reloptions ! for a particular table, the settings it specifies are applied; otherwise the ! global settings are used. See for ! more details on the global settings. Besides the base threshold values and scale factors, there are five ! more autovacuum parameters that can be set for each table in ! pg_class.reloptions. ! The first, autovacuum_enabled, can be set to false to instruct the autovacuum daemon to skip that particular table entirely. In this case autovacuum will only touch the table if it must do so to prevent transaction ID wraparound. The next two parameters, the vacuum cost delay ! (autovacuum_vac_cost_delay) and the vacuum cost limit ! (autovacuum_vac_cost_limit), are used to set ! table-specific values for the feature. ! The last two parameters, (autovacuum_freeze_min_age) and ! (autovacuum_freeze_max_age), are used to set ! table-specific values for and respectively. ! If any of the autovacuum-specific values in ! pg_class.reloptions ! are set to a negative number, or if the field does not contain any ! autovacuum-specific parameters at all in ! pg_class.reloptions for any ! particular table, the corresponding values from ! postgresql.conf are used. ! The WITH clause can specify autovacuum-specific parameters for ! tables while creating them. Similarly, RESET can be used to reset ! autovacuum parameters to their defaults and SET can be used to ! add new autovacuum parameters. These parameters are documented in . When multiple workers are running, the cost limit is balanced among all the running workers, so that the Index: doc/src/sgml/ref/alter_index.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/ref/alter_index.sgml,v retrieving revision 1.14 diff -c -r1.14 alter_index.sgml *** doc/src/sgml/ref/alter_index.sgml 14 Nov 2008 10:22:45 -0000 1.14 --- doc/src/sgml/ref/alter_index.sgml 4 Dec 2008 18:35:30 -0000 *************** *** 23,30 **** ALTER INDEX name RENAME TO new_name ALTER INDEX name SET TABLESPACE tablespace_name ! ALTER INDEX name SET ( storage_parameter = value [, ... ] ) ! ALTER INDEX name RESET ( storage_parameter [, ... ] ) --- 23,30 ---- ALTER INDEX name RENAME TO new_name ALTER INDEX name SET TABLESPACE tablespace_name ! ALTER INDEX name SET ( relation_parameter = value [, ... ] ) ! ALTER INDEX name RESET ( relation_parameter [, ... ] ) *************** *** 60,69 **** ! SET ( storage_parameter = value [, ... ] ) ! This form changes one or more index-method-specific storage parameters for the index. See for details on the available parameters. Note that the index contents --- 60,69 ---- ! SET ( relation_parameter = value [, ... ] ) ! This form changes one or more index-method-specific relation parameters for the index. See for details on the available parameters. Note that the index contents *************** *** 76,85 **** ! RESET ( storage_parameter [, ... ] ) ! This form resets one or more index-method-specific storage parameters to their defaults. As with SET, a REINDEX might be needed to update the index entirely. --- 76,85 ---- ! RESET ( relation_parameter [, ... ] ) ! This form resets one or more index-method-specific relation parameters to their defaults. As with SET, a REINDEX might be needed to update the index entirely. *************** *** 125,134 **** ! storage_parameter ! The name of an index-method-specific storage parameter. --- 125,134 ---- ! relation_parameter ! The name of an index-method-specific relation parameter. *************** *** 137,143 **** value ! The new value for an index-method-specific storage parameter. This might be a number or a word depending on the parameter. --- 137,143 ---- value ! The new value for an index-method-specific relation parameter. This might be a number or a word depending on the parameter. Index: doc/src/sgml/ref/alter_table.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/ref/alter_table.sgml,v retrieving revision 1.101 diff -c -r1.101 alter_table.sgml *** doc/src/sgml/ref/alter_table.sgml 14 Nov 2008 10:22:45 -0000 1.101 --- doc/src/sgml/ref/alter_table.sgml 4 Dec 2008 17:41:25 -0000 *************** *** 53,60 **** CLUSTER ON index_name SET WITHOUT CLUSTER SET WITHOUT OIDS ! SET ( storage_parameter = value [, ... ] ) ! RESET ( storage_parameter [, ... ] ) INHERIT parent_table NO INHERIT parent_table OWNER TO new_owner --- 53,60 ---- CLUSTER ON index_name SET WITHOUT CLUSTER SET WITHOUT OIDS ! SET ( relation_parameter = value [, ... ] ) ! RESET ( relation_parameter [, ... ] ) INHERIT parent_table NO INHERIT parent_table OWNER TO new_owner *************** *** 282,295 **** ! SET ( storage_parameter = value [, ... ] ) ! This form changes one or more storage parameters for the table. See ! for details on the available parameters. Note that the table contents ! will not be modified immediately by this command; depending on the ! parameter you might need to rewrite the table to get the desired effects. That can be done with or one of the forms of ALTER TABLE that forces a table rewrite. --- 282,294 ---- ! SET ( relation_parameter = value [, ... ] ) ! This form changes one or more relation parameters for the table. See ! for details on the available parameters. Depending on the parameter ! you might need to rewrite the table to get the desired effects. That can be done with or one of the forms of ALTER TABLE that forces a table rewrite. *************** *** 299,317 **** While CREATE TABLE allows OIDS to be specified in the WITH (storage_parameter) syntax, ALTER TABLE does not treat OIDS as a ! storage parameter. ! RESET ( storage_parameter [, ... ] ) ! This form resets one or more storage parameters to their defaults. As with SET, a table rewrite might be needed to update the table entirely. --- 298,316 ---- While CREATE TABLE allows OIDS to be specified in the WITH (relation_parameter) syntax, ALTER TABLE does not treat OIDS as a ! relation parameter. ! RESET ( relation_parameter [, ... ] ) ! This form resets one or more relation parameters to their defaults. As with SET, a table rewrite might be needed to update the table entirely. *************** *** 562,571 **** ! storage_parameter ! The name of a table storage parameter. --- 561,570 ---- ! relation_parameter ! The name of a relation parameter. *************** *** 574,580 **** value ! The new value for a table storage parameter. This might be a number or a word depending on the parameter. --- 573,579 ---- value ! The new value for a relation parameter. This might be a number or a word depending on the parameter. Index: doc/src/sgml/ref/create_index.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/ref/create_index.sgml,v retrieving revision 1.69 diff -c -r1.69 create_index.sgml *** doc/src/sgml/ref/create_index.sgml 14 Nov 2008 10:22:46 -0000 1.69 --- doc/src/sgml/ref/create_index.sgml 4 Dec 2008 18:39:57 -0000 *************** *** 23,29 **** CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] name ON table [ USING method ] ( { column | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] ) ! [ WITH ( storage_parameter = value [, ... ] ) ] [ TABLESPACE tablespace ] [ WHERE predicate ] --- 23,29 ---- CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] name ON table [ USING method ] ( { column | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] ) ! [ WITH ( relation_parameter = value [, ... ] ) ] [ TABLESPACE tablespace ] [ WHERE predicate ] *************** *** 227,237 **** ! storage_parameter ! The name of an index-method-specific storage parameter. See ! below for details. --- 227,248 ---- ! relation_parameter ! The name of an index-method-specific relation parameter. See ! for details. ! ! ! ! ! ! value ! ! ! The new value for an index-method-specific relation parameter. ! This might be a number or a word depending on the parameter. *************** *** 259,270 **** ! ! Index Storage Parameters ! The WITH clause can specify storage parameters ! for indexes. Each index method can have its own set of allowed storage parameters. The built-in index methods all accept a single parameter: --- 270,281 ---- ! ! Index Relation Parameters ! The WITH clause can specify relation parameters ! for indexes. Each index method can have its own set of allowed relation parameters. The built-in index methods all accept a single parameter: Index: doc/src/sgml/ref/create_table.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/ref/create_table.sgml,v retrieving revision 1.111 diff -c -r1.111 create_table.sgml *** doc/src/sgml/ref/create_table.sgml 14 Nov 2008 10:22:46 -0000 1.111 --- doc/src/sgml/ref/create_table.sgml 5 Dec 2008 04:16:22 -0000 *************** *** 28,34 **** [, ... ] ] ) [ INHERITS ( parent_table [, ... ] ) ] ! [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace ] --- 28,34 ---- [, ... ] ] ) [ INHERITS ( parent_table [, ... ] ) ] ! [ WITH ( relation_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace ] *************** *** 56,62 **** index_parameters in UNIQUE and PRIMARY KEY constraints are: ! [ WITH ( storage_parameter [= value] [, ... ] ) ] [ USING INDEX TABLESPACE tablespace ] --- 56,62 ---- index_parameters in UNIQUE and PRIMARY KEY constraints are: ! [ WITH ( relation_parameter [= value] [, ... ] ) ] [ USING INDEX TABLESPACE tablespace ] *************** *** 558,569 **** ! WITH ( storage_parameter [= value] [, ... ] ) ! This clause specifies optional storage parameters for a table or index; ! see for more information. The WITH clause for a table can also include OIDS=TRUE (or just OIDS) to specify that rows of the new table --- 558,569 ---- ! WITH ( relation_parameter [= value] [, ... ] ) ! This clause specifies optional parameters for a table or index; ! see for more information. The WITH clause for a table can also include OIDS=TRUE (or just OIDS) to specify that rows of the new table *************** *** 602,608 **** These are obsolescent syntaxes equivalent to WITH (OIDS) and WITH (OIDS=FALSE), respectively. If you wish to give ! both an OIDS setting and storage parameters, you must use the WITH ( ... ) syntax; see above. --- 602,608 ---- These are obsolescent syntaxes equivalent to WITH (OIDS) and WITH (OIDS=FALSE), respectively. If you wish to give ! both an OIDS setting and relation parameters, you must use the WITH ( ... ) syntax; see above. *************** *** 682,703 **** ! ! Storage Parameters ! The WITH clause can specify storage parameters for tables, and for indexes associated with a UNIQUE or ! PRIMARY KEY constraint. Storage parameters for indexes are documented in . The only storage parameter currently ! available for tables is: ! FILLFACTOR The fillfactor for a table is a percentage between 10 and 100. --- 682,703 ---- ! ! Relation Parameters ! The WITH clause can specify relation parameters for tables, and for indexes associated with a UNIQUE or ! PRIMARY KEY constraint. Relation parameters for indexes are documented in . The relation parameters currently ! available for tables are: ! FILLFACTOR (integer) The fillfactor for a table is a percentage between 10 and 100. *************** *** 714,719 **** --- 714,833 ---- + + AUTOVACUUM_ENABLED (boolean) + + + Enables or disables the autovacuum daemon on a particular table. + If true, the autovacuum daemon will initiate a VACUUM operation + on a particular table when the number of updated or deleted tuples exceeds + autovacuum_vac_threshold plus + autovacuum_vac_scale_factor times the number of live tuples + currently estimated to be in the relation. + Similarly, it will initiate an ANALYZE operation when the + number of inserted, updated or deleted tuples exceeds + autovacuum_anl_threshold plus + autovacuum_anl_scale_factor times the number of live tuples + currently estimated to be in the relation. + If false, this table will not be autovacuumed, except to prevent + transaction Id wraparound. See for + more about wraparound prevention. + Observe that this variable inherits its value from the . + + + + + + AUTOVACUUM_VAC_THRESHOLD (integer) + + + Minimum number of updated or deleted tuples before initiate a + VACUUM operation on a particular table. + + + + + + AUTOVACUUM_VAC_SCALE_FACTOR (float4) + + + Multiplier for reltuples to add to + autovacuum_vac_threshold. + + + + + + AUTOVACUUM_ANL_THRESHOLD (integer) + + + Minimum number of inserted, updated, or deleted tuples before initiate an + ANALYZE operation on a particular table. + + + + + + AUTOVACUUM_ANL_SCALE_FACTOR (float4) + + + Multiplier for reltuples to add to + autovacuum_anl_threshold. + + + + + + AUTOVACUUM_VAC_COST_DELAY (integer) + + + Custom parameter. A + -1 (or indeed any negative value) indicates that the + system-wide default (autovacuum_vacuum_cost_delay) should be + used for this particular value. + + + + + + AUTOVACUUM_VAC_COST_LIMIT (integer) + + + Custom parameter. A + -1 (or indeed any negative value) indicates that the + system-wide default (autovacuum_vacuum_cost_limit) should be + used for this particular value. + + + + + + AUTOVACUUM_FREEZE_MIN_AGE (integer) + + + Custom parameter. Also, + autovacuum will ignore attempts to set a per-table + autovacuum_freeze_min_age larger than the half system-wide + setting. + + + + + + AUTOVACUUM_FREEZE_MAX_AGE (integer) + + + Custom parameter. Also, + autovacuum will ignore attempts to set a per-table + autovacuum_freeze_max_age larger than the system-wide setting + (it can only be set smaller). Note that while you can set + autovacuum_freeze_max_age very small, or even zero, this is + usually unwise since it will force frequent vacuuming. + + + + *************** *** 1069,1075 **** The WITH clause is a PostgreSQL ! extension; neither storage parameters nor OIDs are in the standard. --- 1183,1189 ---- The WITH clause is a PostgreSQL ! extension; neither relation parameters nor OIDs are in the standard. Index: doc/src/sgml/ref/create_table_as.sgml =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/doc/src/sgml/ref/create_table_as.sgml,v retrieving revision 1.40 diff -c -r1.40 create_table_as.sgml *** doc/src/sgml/ref/create_table_as.sgml 20 Nov 2008 14:04:45 -0000 1.40 --- doc/src/sgml/ref/create_table_as.sgml 4 Dec 2008 18:41:46 -0000 *************** *** 23,29 **** CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name [ (column_name [, ...] ) ] ! [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace ] AS query --- 23,29 ---- CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name [ (column_name [, ...] ) ] ! [ WITH ( relation_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace ] AS query *************** *** 104,115 **** ! WITH ( storage_parameter [= value] [, ... ] ) ! This clause specifies optional storage parameters for the new table; ! see for more information. The WITH clause can also include OIDS=TRUE (or just OIDS) to specify that rows of the new table --- 104,115 ---- ! WITH ( relation_parameter [= value] [, ... ] ) ! This clause specifies optional relation parameters for the new table; ! see for more information. The WITH clause can also include OIDS=TRUE (or just OIDS) to specify that rows of the new table *************** *** 128,134 **** These are obsolescent syntaxes equivalent to WITH (OIDS) and WITH (OIDS=FALSE), respectively. If you wish to give ! both an OIDS setting and storage parameters, you must use the WITH ( ... ) syntax; see above. --- 128,134 ---- These are obsolescent syntaxes equivalent to WITH (OIDS) and WITH (OIDS=FALSE), respectively. If you wish to give ! both an OIDS setting and relation parameters, you must use the WITH ( ... ) syntax; see above. *************** *** 321,327 **** The WITH clause is a PostgreSQL ! extension; neither storage parameters nor OIDs are in the standard. --- 321,327 ---- The WITH clause is a PostgreSQL ! extension; neither relation parameters nor OIDs are in the standard. Index: src/backend/access/common/reloptions.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/common/reloptions.c,v retrieving revision 1.11 diff -c -r1.11 reloptions.c *** src/backend/access/common/reloptions.c 23 Jul 2008 17:29:53 -0000 1.11 --- src/backend/access/common/reloptions.c 4 Dec 2008 18:48:50 -0000 *************** *** 24,29 **** --- 24,193 ---- #include "utils/guc.h" #include "utils/rel.h" + /* + * Contents of pg_class.reloptions + * + * To add an option: + * + * (i) decide on a class (integer, double, bool), name, default value, upper + * and lower bounds (if applicable). + * + * (ii) add a record below. + * + * (iii) don't forget to document the option + * + * PS> we don't handle "oids" in relOpts because i'll be or have been + * handled by interpretOidsOption(). + */ + + static const struct relopt_bool relOptAVEnabled = + { + { + "autovacuum_enabled", + "Enables autovacuum in this relation", + RELOPT_TYPE_BOOL, + RELOPT_KIND_HEAP + }, + false + }; + + static const struct relopt_int relOptFillFactor = + { + { + "fillfactor", + "Packs table pages only to this percentage", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP | RELOPT_KIND_INDEX + }, + 100, + 10, + 100 + }; + + static const struct relopt_int relOptAVVacThreshold = + { + { + "autovacuum_vac_threshold", + "Minimum number of tuple updates or deletes prior to vacuum", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP + }, + 50, + 0, + INT_MAX + }; + + static const struct relopt_int relOptAVAnlThreshold = + { + { + "autovacuum_anl_threshold", + "Minimum number of tuple inserts, updates or deletes prior to analyze", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP + }, + 50, + 0, + INT_MAX + }; + + static const struct relopt_int relOptAVVacCostDelay = + { + { + "autovacuum_vac_cost_delay", + "Vacuum cost delay in milliseconds, for autovacuum", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP + }, + 20, + -1, + 1000 + }; + + static const struct relopt_int relOptAVVacCostLimit = + { + { + "autovacuum_vac_cost_limit", + "Vacuum cost ammount available before napping, for autovacuum", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP + }, + -1, + -1, + 10000 + }; + + static const struct relopt_int relOptAVFreezeMinAge = + { + { + "autovacuum_freeze_min_age", + "Minimum age at which VACUUM should freeze a table row, for autovacuum", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP + }, + 100000000, + 0, + 1000000000 + }; + + static const struct relopt_int relOptAVFreezeMaxAge = + { + { + "autovacuum_freeze_max_age", + "Age at which to autovacuum a table to prevent transaction ID wraparound", + RELOPT_TYPE_INT, + RELOPT_KIND_HEAP + }, + 200000000, + 100000000, + 2000000000 + }; + + static const struct relopt_real relOptAVVacScaleFactor = + { + { + "autovacuum_vac_scale_factor", + "Number of tuples inserts, updates or deletes prior to vacuum as a fraction of reltuples", + RELOPT_TYPE_REAL, + RELOPT_KIND_HEAP + }, + 0.2, + 0.0, + 100.0 + }; + + static const struct relopt_real relOptAVAnlScaleFactor = + { + { + "autovacuum_anl_scale_factor", + "Number of tuples inserts, updates or deletes prior to analyze as a fraction of reltuples", + RELOPT_TYPE_REAL, + RELOPT_KIND_HEAP + }, + 0.1, + 0.0, + 100.0 + }; + + static const struct relopt_gen * const relOpts[] = + { + (const struct relopt_gen *) &relOptAVEnabled, + (const struct relopt_gen *) &relOptFillFactor, + (const struct relopt_gen *) &relOptAVVacThreshold, + (const struct relopt_gen *) &relOptAVAnlThreshold, + (const struct relopt_gen *) &relOptAVVacCostDelay, + (const struct relopt_gen *) &relOptAVVacCostLimit, + (const struct relopt_gen *) &relOptAVFreezeMinAge, + (const struct relopt_gen *) &relOptAVFreezeMaxAge, + (const struct relopt_gen *) &relOptAVVacScaleFactor, + (const struct relopt_gen *) &relOptAVAnlScaleFactor, + NULL + }; + + /* local function prototypes */ + static bool containsOption(List *values, const char *opt); + static char *getRelOption(Datum options, char *opt); + static void parseRelOptions(Datum options, Datum data, bool validate, + int minFillFactor, uint16 reloptkind); /* * Transform a relation options list (list of DefElem) into the text array *************** *** 73,99 **** for (i = 0; i < noldoptions; i++) { ! text *oldoption = DatumGetTextP(oldoptions[i]); ! char *text_str = VARDATA(oldoption); ! int text_len = VARSIZE(oldoption) - VARHDRSZ; /* Search for a match in defList */ foreach(cell, defList) { DefElem *def = lfirst(cell); ! int kw_len = strlen(def->defname); ! if (text_len > kw_len && text_str[kw_len] == '=' && ! pg_strncasecmp(text_str, def->defname, kw_len) == 0) break; } ! if (!cell) ! { ! /* No match, so keep old option */ astate = accumArrayResult(astate, oldoptions[i], false, TEXTOID, CurrentMemoryContext); - } } } --- 237,261 ---- for (i = 0; i < noldoptions; i++) { ! char *textstr = TextDatumGetCString(oldoptions[i]); ! int tlen = strlen(textstr); /* Search for a match in defList */ foreach(cell, defList) { DefElem *def = lfirst(cell); ! int klen = strlen(def->defname); ! if (tlen > klen && textstr[klen] == '=' && ! pg_strncasecmp(textstr, def->defname, klen) == 0) break; } ! ! /* No match, so keep old option */ ! if (cell == NULL) astate = accumArrayResult(astate, oldoptions[i], false, TEXTOID, CurrentMemoryContext); } } *************** *** 108,113 **** --- 270,292 ---- if (isReset) { + /* + * Check wether the option in RESET is valid + * + * TODO we're not checking the option kind but ... + */ + int i; + bool found = false; + + for (i = 0; relOpts[i]; i++) + if (pg_strcasecmp(def->defname, relOpts[i]->name) == 0) + found = true; + + if (!found) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized parameter \"%s\"", def->defname))); + if (def->arg != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), *************** *** 118,136 **** text *t; const char *value; Size len; if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0) continue; - /* - * Flatten the DefElem into a text string like "name=arg". If we - * have just "name", assume "name=true" is meant. - */ if (def->arg != NULL) value = defGetString(def); else ! value = "true"; len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value); /* +1 leaves room for sprintf's trailing null */ t = (text *) palloc(len + 1); SET_VARSIZE(t, len); --- 297,346 ---- text *t; const char *value; Size len; + int i; if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0) continue; if (def->arg != NULL) value = defGetString(def); else ! value = '\0'; /* parseRelOptions() will complain */ ! ! /* ! * Boolean types can be represented with different strings ! * so we transform it to be 'true' or 'false. ! * Also, if we have an argument that doesn't have a value ! * we assume that its value is 'true'. ! */ ! for (i = 0; relOpts[i]; i++) ! { ! if (relOpts[i]->type == RELOPT_TYPE_BOOL && ! pg_strcasecmp(def->defname, relOpts[i]->name) == 0) ! { ! if (def->arg != NULL) ! { ! bool val; ! ! parse_bool(defGetString(def), &val); ! if (val) ! value = "true"; ! else ! value = "false"; ! } ! else ! { ! value = "true"; /* no argument means 'true' */ ! } ! break; ! } ! } ! ! /* ! * Flatten the DefElem into a text string like "name=arg". ! */ len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value); + /* +1 leaves room for sprintf's trailing null */ t = (text *) palloc(len + 1); SET_VARSIZE(t, len); *************** *** 188,226 **** *p++ = '\0'; val = (Node *) makeString(pstrdup(p)); } result = lappend(result, makeDefElem(pstrdup(s), val)); } return result; } /* * Interpret reloptions that are given in text-array format. * * options: array of "keyword=value" strings, as built by transformRelOptions ! * numkeywords: number of legal keywords ! * keywords: the allowed keywords ! * values: output area ! * validate: if true, throw error for unrecognized keywords. ! * ! * The keywords and values arrays must both be of length numkeywords. ! * The values entry corresponding to a keyword is set to a palloc'd string ! * containing the corresponding value, or NULL if the keyword does not appear. ! */ ! void ! parseRelOptions(Datum options, int numkeywords, const char *const * keywords, ! char **values, bool validate) { ! ArrayType *array; ! Datum *optiondatums; ! int noptions; ! int i; ! ! /* Initialize to "all defaulted" */ ! MemSet(values, 0, numkeywords * sizeof(char *)); ! /* Done if no options */ if (!PointerIsValid(DatumGetPointer(options))) return; --- 398,578 ---- *p++ = '\0'; val = (Node *) makeString(pstrdup(p)); } + result = lappend(result, makeDefElem(pstrdup(s), val)); } return result; } + /* + * This function returns a palloc'd string or NULL (if not found) containing + * the value of opt. + * + * Don't use this function directly. Consider using getXXXRelOption() that + * converts the value for the appropriated type instead. + */ + static char * + getRelOption(Datum options, char *opt) + { + char *result = NULL; + ArrayType *array; + Datum *optiondatums; + int noptions; + int i; + + /* Nothing to do if no options */ + if (!PointerIsValid(DatumGetPointer(options))) + return result; + + array = DatumGetArrayTypeP(options); + + Assert(ARR_ELEMTYPE(array) == TEXTOID); + + deconstruct_array(array, TEXTOID, -1, false, 'i', + &optiondatums, NULL, &noptions); + + for (i = 0; i < noptions; i++) + { + char *key; + char *value; + + key = TextDatumGetCString(optiondatums[i]); + value = strchr(key, '='); + if (value) + *value++ = '\0'; + + /* Search for a match in reloptions */ + if (pg_strcasecmp(key, opt) == 0) + { + int vlen = strlen(value); + + result = (char *) palloc(vlen + 1); + memcpy(result, value, vlen); + result[vlen] = '\0'; + + break; + } + } + + return result; + } + + /* + * "Converts" a string to string + * + * A boolean value is returned meaning the conversion was succeed or not. + */ + bool + getCharRelOption(Datum options, char *opt, char *result) + { + result = getRelOption(options, opt); + + if (result) + return true; + else + return false; + } + + /* + * Converts a string to boolean + * + * A boolean value is returned meaning the conversion was succeed or not. + */ + bool + getBoolRelOption(Datum options, char *opt, bool *result) + { + const char *tmp = getRelOption(options, opt); + + if (tmp && parse_bool(tmp, result)) + return true; + else + return false; + } + + /* + * Converts a string to integer + * + * A boolean value is returned meaning the conversion was succeed or not. + */ + bool + getIntRelOption(Datum options, char *opt, int *result) + { + const char *tmp = getRelOption(options, opt); + + if (tmp) + { + *result = atoi(tmp); + return true; + } + else + { + return false; + } + } + + /* + * Converts a string to float + * + * A boolean value is returned meaning if the conversion was succeed or not. + */ + bool + getDoubleRelOption(Datum options, char *opt, double *result) + { + const char *tmp = getRelOption(options, opt); + + if (tmp) + { + *result = atof(tmp); + return true; + } + else + { + return false; + } + } + + /* + * Searchs for an option on list + */ + static bool containsOption(List *values, const char *opt) + { + ListCell *cell; + + foreach(cell, values) + { + DefElem *d = lfirst(cell); + if (pg_strcasecmp(d->defname, opt) == 0) + return true; + } + + return false; + } + /* * Interpret reloptions that are given in text-array format. * * options: array of "keyword=value" strings, as built by transformRelOptions ! * data: output area ! * validate: if true, throw error for unrecognized keywords ! * minFillFactor: some AMs have different fillfactor values ! * reloptkind: heap or index? ! * ! * The options are matched against relOpts[]. If an option matches, stores ! * it in value list. ! */ ! static void ! parseRelOptions(Datum options, Datum data, bool validate, int minFillFactor, ! uint16 reloptkind) { ! List *values = NIL; ! ArrayType *array; ! Datum *optiondatums; ! int noptions; ! int i; ! /* If no options, we're done */ if (!PointerIsValid(DatumGetPointer(options))) return; *************** *** 233,356 **** for (i = 0; i < noptions; i++) { ! text *optiontext = DatumGetTextP(optiondatums[i]); ! char *text_str = VARDATA(optiontext); ! int text_len = VARSIZE(optiontext) - VARHDRSZ; ! int j; /* Search for a match in keywords */ ! for (j = 0; j < numkeywords; j++) { ! int kw_len = strlen(keywords[j]); ! if (text_len > kw_len && text_str[kw_len] == '=' && ! pg_strncasecmp(text_str, keywords[j], kw_len) == 0) ! { ! char *value; ! int value_len; ! if (values[j] && validate) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("parameter \"%s\" specified more than once", ! keywords[j]))); ! value_len = text_len - kw_len - 1; ! value = (char *) palloc(value_len + 1); ! memcpy(value, text_str + kw_len + 1, value_len); ! value[value_len] = '\0'; ! values[j] = value; break; } } ! if (j >= numkeywords && validate) { ! char *s; ! char *p; s = TextDatumGetCString(optiondatums[i]); p = strchr(s, '='); if (p) *p = '\0'; ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized parameter \"%s\"", s))); } } } /* ! * Parse reloptions for anything using StdRdOptions (ie, fillfactor only) */ bytea * ! default_reloptions(Datum reloptions, bool validate, ! int minFillfactor, int defaultFillfactor) { ! static const char *const default_keywords[1] = {"fillfactor"}; ! char *values[1]; ! int fillfactor; ! StdRdOptions *result; ! parseRelOptions(reloptions, 1, default_keywords, values, validate); ! /* ! * If no options, we can just return NULL rather than doing anything. ! * (defaultFillfactor is thus not used, but we require callers to pass it ! * anyway since we would need it if more options were added.) */ ! if (values[0] == NULL) ! return NULL; ! ! if (!parse_int(values[0], &fillfactor, 0, NULL)) ! { ! if (validate) ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("fillfactor must be an integer: \"%s\"", ! values[0]))); ! return NULL; ! } ! ! if (fillfactor < minFillfactor || fillfactor > 100) ! { ! if (validate) ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("fillfactor=%d is out of range (should be between %d and 100)", ! fillfactor, minFillfactor))); ! return NULL; ! } ! ! result = (StdRdOptions *) palloc(sizeof(StdRdOptions)); ! SET_VARSIZE(result, sizeof(StdRdOptions)); ! ! result->fillfactor = fillfactor; ! return (bytea *) result; } /* ! * Parse options for heaps (and perhaps someday toast tables). */ bytea * ! heap_reloptions(char relkind, Datum reloptions, bool validate) { ! return default_reloptions(reloptions, validate, ! HEAP_MIN_FILLFACTOR, ! HEAP_DEFAULT_FILLFACTOR); } /* ! * Parse options for indexes. ! * ! * amoptions Oid of option parser ! * reloptions options as text[] datum ! * validate error flag */ bytea * ! index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate) { FmgrInfo flinfo; FunctionCallInfoData fcinfo; --- 585,777 ---- for (i = 0; i < noptions; i++) { ! text *optiontext = DatumGetTextP(optiondatums[i]); ! char *textstr = VARDATA(optiontext); ! int tlen = VARSIZE(optiontext) - VARHDRSZ; ! int j; ! bool found = false; /* Search for a match in keywords */ ! for (j = 0; relOpts[j]; j++) { ! int klen; ! /* Skip options that are not the same kind */ ! if (!(relOpts[j]->kind & reloptkind)) ! continue; ! ! klen = strlen(relOpts[j]->name); ! if (tlen > klen && textstr[klen] == '=' && ! pg_strncasecmp(textstr, relOpts[j]->name, klen) == 0) ! { ! Node *vnode; ! char *value; ! int vlen; ! ! /* Search for a match in a list-being-built only iff we're validating */ ! if (validate && containsOption(values, relOpts[j]->name)) ! { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("parameter \"%s\" specified more than once", relOpts[j]->name))); ! return; ! } ! ! vlen = tlen - klen - 1; ! value = (char *) palloc(vlen + 1); ! memcpy(value, textstr + klen + 1, vlen); ! value[vlen] = '\0'; ! ! if (relOpts[j]->type == RELOPT_TYPE_BOOL) ! { ! bool pvalue; ! ! if (!parse_bool(value, &pvalue) && validate) ! { ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("invalid input value for parameter %s: \"%s\"", ! relOpts[j]->name, value), ! errhint("value must be a boolean"))); ! return; ! } ! } ! else if (relOpts[j]->type == RELOPT_TYPE_INT) ! { ! int pvalue; ! struct relopt_int *opt = (struct relopt_int *) relOpts[j]; ! ! if (!parse_int(value, &pvalue, 0, NULL) && validate) ! { ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("invalid input value for parameter %s: \"%s\"", ! relOpts[j]->name, value), ! errhint("value must be an integer"))); ! return; ! } ! ! if ((pvalue < opt->min || pvalue > opt->max) && validate) ! { ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("%s=%s is out of range (should be between %d and %d)", ! relOpts[j]->name, value, opt->min, opt->max))); ! return; ! } ! ! /* ! * Especial check for fillfactor because minimum fillfactor values ! * are AMs and/or heap dependant. We don't need to check upper ! * limit because we already did it above. ! */ ! if (pg_strcasecmp(relOpts[j]->name, "fillfactor") == 0 && ! pvalue < minFillFactor && validate) ! { ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("fillfactor=%s is out of range (should be between %d and 100)", ! value, minFillFactor))); ! return; ! } ! } ! else if (relOpts[j]->type == RELOPT_TYPE_REAL) ! { ! double pvalue; ! struct relopt_real *opt = (struct relopt_real *) relOpts[j]; ! ! if (!parse_real(value, &pvalue) && validate) ! { ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("invalid input value for parameter %s: \"%s\"", ! relOpts[j]->name, value), ! errhint("value must be a float"))); ! return; ! } ! ! if ((pvalue < opt->min || pvalue > opt->max) && validate) ! { ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("%s=%s is out of range (should be between %f and %f)", ! relOpts[j]->name, value, opt->min, opt->max))); ! return; ! } ! } ! ! vnode = (Node *) makeString(value); ! values = lappend(values, makeDefElem(pstrdup(relOpts[j]->name), vnode)); ! ! found = true; break; } } ! ! if (!found && validate) { ! char *s, *p; s = TextDatumGetCString(optiondatums[i]); p = strchr(s, '='); if (p) *p = '\0'; + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized parameter \"%s\"", s))); } } + + /* Transform list in ArrayType so we can store it */ + data = transformRelOptions((Datum) 0, values, true, false); } /* ! * Parse reloptions for generic uses */ bytea * ! defaultRelOptions(Datum reloptions, bool validate, ! int minFillFactor, uint16 reloptkind) { ! Datum data = 0; ! bytea *result; ! parseRelOptions(reloptions, data, validate, minFillFactor, reloptkind); ! /* ! * We can just return NULL when there is no options or we don't need ! * the pre-parsed options */ ! if (!PointerIsValid(DatumGetPointer(data))) ! result = NULL; ! else ! result = (bytea *) data; ! return result; } /* ! * Parse options for heaps */ bytea * ! heapRelOptions(Datum reloptions, bool validate) { ! return defaultRelOptions(reloptions, validate, ! HEAP_MIN_FILLFACTOR, ! RELOPT_KIND_HEAP); } /* ! * Parse options for indexes */ bytea * ! indexRelOptions(RegProcedure amoptions, Datum reloptions, ! bool validate) { FmgrInfo flinfo; FunctionCallInfoData fcinfo; Index: src/backend/access/gin/ginutil.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/gin/ginutil.c,v retrieving revision 1.18 diff -c -r1.18 ginutil.c *** src/backend/access/gin/ginutil.c 3 Nov 2008 20:47:48 -0000 1.18 --- src/backend/access/gin/ginutil.c 3 Dec 2008 17:02:44 -0000 *************** *** 313,332 **** Datum ginoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; ! /* ! * It's not clear that fillfactor is useful for GIN, but for the moment ! * we'll accept it anyway. (It won't do anything...) ! */ ! #define GIN_MIN_FILLFACTOR 10 ! #define GIN_DEFAULT_FILLFACTOR 100 - result = default_reloptions(reloptions, validate, - GIN_MIN_FILLFACTOR, - GIN_DEFAULT_FILLFACTOR); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); --- 313,326 ---- Datum ginoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; ! result = defaultRelOptions(reloptions, validate, ! GIN_MIN_FILLFACTOR, ! RELOPT_KIND_INDEX); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); Index: src/backend/access/gist/gistutil.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/gist/gistutil.c,v retrieving revision 1.31 diff -c -r1.31 gistutil.c *** src/backend/access/gist/gistutil.c 30 Sep 2008 10:52:10 -0000 1.31 --- src/backend/access/gist/gistutil.c 3 Dec 2008 17:03:20 -0000 *************** *** 666,678 **** Datum gistoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; - result = default_reloptions(reloptions, validate, - GIST_MIN_FILLFACTOR, - GIST_DEFAULT_FILLFACTOR); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); --- 666,679 ---- Datum gistoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; ! ! result = defaultRelOptions(reloptions, validate, ! GIST_MIN_FILLFACTOR, ! RELOPT_KIND_INDEX); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); Index: src/backend/access/hash/hashutil.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/hash/hashutil.c,v retrieving revision 1.57 diff -c -r1.57 hashutil.c *** src/backend/access/hash/hashutil.c 15 Sep 2008 18:43:41 -0000 1.57 --- src/backend/access/hash/hashutil.c 3 Dec 2008 17:04:23 -0000 *************** *** 220,232 **** Datum hashoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; ! ! result = default_reloptions(reloptions, validate, ! HASH_MIN_FILLFACTOR, ! HASH_DEFAULT_FILLFACTOR); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); --- 220,233 ---- Datum hashoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; ! ! result = defaultRelOptions(reloptions, validate, ! HASH_MIN_FILLFACTOR, ! RELOPT_KIND_INDEX); ! if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); Index: src/backend/access/heap/hio.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/heap/hio.c,v retrieving revision 1.74 diff -c -r1.74 hio.c *** src/backend/access/heap/hio.c 6 Nov 2008 20:51:14 -0000 1.74 --- src/backend/access/heap/hio.c 3 Dec 2008 17:06:08 -0000 *************** *** 176,183 **** (unsigned long) MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ ! saveFreeSpace = RelationGetTargetPageFreeSpace(relation, ! HEAP_DEFAULT_FILLFACTOR); if (otherBuffer != InvalidBuffer) otherBlock = BufferGetBlockNumber(otherBuffer); --- 176,183 ---- (unsigned long) MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ ! saveFreeSpace = RelationGetTargetPageFreeSpace(relation, ! HEAP_DEFAULT_FILLFACTOR); if (otherBuffer != InvalidBuffer) otherBlock = BufferGetBlockNumber(otherBuffer); Index: src/backend/access/heap/pruneheap.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/heap/pruneheap.c,v retrieving revision 1.16 diff -c -r1.16 pruneheap.c *** src/backend/access/heap/pruneheap.c 13 Jul 2008 20:45:47 -0000 1.16 --- src/backend/access/heap/pruneheap.c 3 Dec 2008 17:07:19 -0000 *************** *** 96,103 **** * important than sometimes getting a wrong answer in what is after all * just a heuristic estimate. */ ! minfree = RelationGetTargetPageFreeSpace(relation, ! HEAP_DEFAULT_FILLFACTOR); minfree = Max(minfree, BLCKSZ / 10); if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree) --- 96,102 ---- * important than sometimes getting a wrong answer in what is after all * just a heuristic estimate. */ ! minfree = RelationGetTargetPageFreeSpace(relation, HEAP_DEFAULT_FILLFACTOR); minfree = Max(minfree, BLCKSZ / 10); if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree) Index: src/backend/access/heap/rewriteheap.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/heap/rewriteheap.c,v retrieving revision 1.16 diff -c -r1.16 rewriteheap.c *** src/backend/access/heap/rewriteheap.c 6 Nov 2008 20:51:14 -0000 1.16 --- src/backend/access/heap/rewriteheap.c 3 Dec 2008 17:08:03 -0000 *************** *** 594,601 **** (unsigned long) MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ ! saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel, ! HEAP_DEFAULT_FILLFACTOR); /* Now we can check to see if there's enough free space already. */ if (state->rs_buffer_valid) --- 594,601 ---- (unsigned long) MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ ! saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel, ! HEAP_DEFAULT_FILLFACTOR); /* Now we can check to see if there's enough free space already. */ if (state->rs_buffer_valid) Index: src/backend/access/nbtree/nbtinsert.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/nbtree/nbtinsert.c,v retrieving revision 1.168 diff -c -r1.168 nbtinsert.c *** src/backend/access/nbtree/nbtinsert.c 3 Nov 2008 20:47:48 -0000 1.168 --- src/backend/access/nbtree/nbtinsert.c 3 Dec 2008 17:09:04 -0000 *************** *** 1233,1240 **** state.is_rightmost = P_RIGHTMOST(opaque); state.have_split = false; if (state.is_leaf) ! state.fillfactor = RelationGetFillFactor(rel, ! BTREE_DEFAULT_FILLFACTOR); else state.fillfactor = BTREE_NONLEAF_FILLFACTOR; state.newitemonleft = false; /* these just to keep compiler quiet */ --- 1233,1239 ---- state.is_rightmost = P_RIGHTMOST(opaque); state.have_split = false; if (state.is_leaf) ! state.fillfactor = RelationGetFillFactor(rel, BTREE_DEFAULT_FILLFACTOR); else state.fillfactor = BTREE_NONLEAF_FILLFACTOR; state.newitemonleft = false; /* these just to keep compiler quiet */ Index: src/backend/access/nbtree/nbtsort.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/nbtree/nbtsort.c,v retrieving revision 1.118 diff -c -r1.118 nbtsort.c *** src/backend/access/nbtree/nbtsort.c 30 Sep 2008 10:52:10 -0000 1.118 --- src/backend/access/nbtree/nbtsort.c 3 Dec 2008 17:09:48 -0000 *************** *** 339,346 **** if (level > 0) state->btps_full = (BLCKSZ * (100 - BTREE_NONLEAF_FILLFACTOR) / 100); else ! state->btps_full = RelationGetTargetPageFreeSpace(wstate->index, ! BTREE_DEFAULT_FILLFACTOR); /* no parent level, yet */ state->btps_next = NULL; --- 339,346 ---- if (level > 0) state->btps_full = (BLCKSZ * (100 - BTREE_NONLEAF_FILLFACTOR) / 100); else ! state->btps_full = RelationGetTargetPageFreeSpace(wstate->index, ! BTREE_DEFAULT_FILLFACTOR); /* no parent level, yet */ state->btps_next = NULL; Index: src/backend/access/nbtree/nbtutils.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/nbtree/nbtutils.c,v retrieving revision 1.91 diff -c -r1.91 nbtutils.c *** src/backend/access/nbtree/nbtutils.c 19 Jun 2008 00:46:03 -0000 1.91 --- src/backend/access/nbtree/nbtutils.c 3 Dec 2008 17:10:44 -0000 *************** *** 1398,1410 **** Datum btoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; - result = default_reloptions(reloptions, validate, - BTREE_MIN_FILLFACTOR, - BTREE_DEFAULT_FILLFACTOR); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); --- 1398,1411 ---- Datum btoptions(PG_FUNCTION_ARGS) { ! Datum reloptions = PG_GETARG_DATUM(0); ! bool validate = PG_GETARG_BOOL(1); ! bytea *result; ! ! result = defaultRelOptions(reloptions, validate, ! BTREE_MIN_FILLFACTOR, ! RELOPT_KIND_INDEX); if (result) PG_RETURN_BYTEA_P(result); PG_RETURN_NULL(); Index: src/backend/catalog/Makefile =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/catalog/Makefile,v retrieving revision 1.67 diff -c -r1.67 Makefile *** src/backend/catalog/Makefile 19 Nov 2008 10:34:51 -0000 1.67 --- src/backend/catalog/Makefile 29 Nov 2008 17:13:33 -0000 *************** *** 26,32 **** # indexing.h had better be last, and toasting.h just before it. POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ ! pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \ pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \ pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ --- 26,32 ---- # indexing.h had better be last, and toasting.h just before it. POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ ! pg_proc.h pg_type.h pg_attribute.h pg_class.h \ pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \ pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ Index: src/backend/commands/indexcmds.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/commands/indexcmds.c,v retrieving revision 1.180 diff -c -r1.180 indexcmds.c *** src/backend/commands/indexcmds.c 13 Oct 2008 16:25:19 -0000 1.180 --- src/backend/commands/indexcmds.c 3 Dec 2008 17:11:57 -0000 *************** *** 400,406 **** */ reloptions = transformRelOptions((Datum) 0, options, false, false); ! (void) index_reloptions(amoptions, reloptions, true); /* * Prepare arguments for index_create, primarily an IndexInfo structure. --- 400,406 ---- */ reloptions = transformRelOptions((Datum) 0, options, false, false); ! (void) indexRelOptions(amoptions, reloptions, true); /* * Prepare arguments for index_create, primarily an IndexInfo structure. Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/commands/tablecmds.c,v retrieving revision 1.271 diff -c -r1.271 tablecmds.c *** src/backend/commands/tablecmds.c 19 Nov 2008 10:34:51 -0000 1.271 --- src/backend/commands/tablecmds.c 3 Dec 2008 17:13:21 -0000 *************** *** 419,425 **** */ reloptions = transformRelOptions((Datum) 0, stmt->options, true, false); ! (void) heap_reloptions(relkind, reloptions, true); /* * Look up inheritance ancestors and generate relation schema, including --- 419,425 ---- */ reloptions = transformRelOptions((Datum) 0, stmt->options, true, false); ! (void) heapRelOptions(reloptions, true); /* * Look up inheritance ancestors and generate relation schema, including *************** *** 6424,6433 **** { case RELKIND_RELATION: case RELKIND_TOASTVALUE: ! (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true); break; case RELKIND_INDEX: ! (void) index_reloptions(rel->rd_am->amoptions, newOptions, true); break; default: ereport(ERROR, --- 6424,6433 ---- { case RELKIND_RELATION: case RELKIND_TOASTVALUE: ! (void) heapRelOptions(newOptions, true); break; case RELKIND_INDEX: ! (void) indexRelOptions(rel->rd_am->amoptions, newOptions, true); break; default: ereport(ERROR, Index: src/backend/commands/vacuum.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/commands/vacuum.c,v retrieving revision 1.382 diff -c -r1.382 vacuum.c *** src/backend/commands/vacuum.c 3 Dec 2008 13:05:22 -0000 1.382 --- src/backend/commands/vacuum.c 3 Dec 2008 17:13:54 -0000 *************** *** 3796,3803 **** Size freespace = PageGetExactFreeSpace(page); Size targetfree; ! targetfree = RelationGetTargetPageFreeSpace(relation, ! HEAP_DEFAULT_FILLFACTOR); if (freespace > targetfree) return freespace - targetfree; else --- 3796,3803 ---- Size freespace = PageGetExactFreeSpace(page); Size targetfree; ! targetfree = RelationGetTargetPageFreeSpace(relation, ! HEAP_DEFAULT_FILLFACTOR); if (freespace > targetfree) return freespace - targetfree; else Index: src/backend/executor/execMain.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/executor/execMain.c,v retrieving revision 1.319 diff -c -r1.319 execMain.c *** src/backend/executor/execMain.c 30 Nov 2008 20:51:25 -0000 1.319 --- src/backend/executor/execMain.c 3 Dec 2008 17:14:54 -0000 *************** *** 2789,2795 **** into->options, true, false); ! (void) heap_reloptions(RELKIND_RELATION, reloptions, true); /* Copy the tupdesc because heap_create_with_catalog modifies it */ tupdesc = CreateTupleDescCopy(queryDesc->tupDesc); --- 2789,2795 ---- into->options, true, false); ! (void) heapRelOptions(reloptions, true); /* Copy the tupdesc because heap_create_with_catalog modifies it */ tupdesc = CreateTupleDescCopy(queryDesc->tupDesc); Index: src/backend/postmaster/autovacuum.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/postmaster/autovacuum.c,v retrieving revision 1.88 diff -c -r1.88 autovacuum.c *** src/backend/postmaster/autovacuum.c 4 Dec 2008 11:42:24 -0000 1.88 --- src/backend/postmaster/autovacuum.c 4 Dec 2008 20:50:07 -0000 *************** *** 69,80 **** #include "access/genam.h" #include "access/heapam.h" #include "access/transam.h" #include "access/xact.h" #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" - #include "catalog/pg_autovacuum.h" #include "catalog/pg_database.h" #include "commands/dbcommands.h" #include "commands/vacuum.h" --- 69,80 ---- #include "access/genam.h" #include "access/heapam.h" + #include "access/reloptions.h" #include "access/transam.h" #include "access/xact.h" #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_database.h" #include "commands/dbcommands.h" #include "commands/vacuum.h" *************** *** 281,295 **** static void FreeWorkerInfo(int code, Datum arg); static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map); ! static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm, ! Form_pg_class classForm, PgStat_StatTabEntry *tabentry, bool *dovacuum, bool *doanalyze, bool *wraparound); static void autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy); - static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid, - HTAB *table_toast_map); static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared, PgStat_StatDBEntry *dbentry); --- 281,292 ---- static void FreeWorkerInfo(int code, Datum arg); static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map); ! static void relation_needs_vacanalyze(Oid relid, Form_pg_class classForm, Datum reloptions, PgStat_StatTabEntry *tabentry, bool *dovacuum, bool *doanalyze, bool *wraparound); static void autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy); static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared, PgStat_StatDBEntry *dbentry); *************** *** 1814,1821 **** static void do_autovacuum(void) { ! Relation classRel, ! avRel; HeapTuple tuple; HeapScanDesc relScan; Form_pg_database dbForm; --- 1811,1817 ---- static void do_autovacuum(void) { ! Relation classRel; HeapTuple tuple; HeapScanDesc relScan; Form_pg_database dbForm; *************** *** 1882,1888 **** shared = pgstat_fetch_stat_dbentry(InvalidOid); classRel = heap_open(RelationRelationId, AccessShareLock); - avRel = heap_open(AutovacuumRelationId, AccessShareLock); /* create hash table for toast <-> main relid mapping */ MemSet(&ctl, 0, sizeof(ctl)); --- 1878,1883 ---- *************** *** 1901,1909 **** * We do this in two passes: on the first one we collect the list of * plain relations, and on the second one we collect TOAST tables. * The reason for doing the second pass is that during it we want to use ! * the main relation's pg_autovacuum entry if the TOAST table does not have ! * any, and we cannot obtain it unless we know beforehand what's the main ! * table OID. * * We need to check TOAST tables separately because in cases with short, * wide tables there might be proportionally much more activity in the --- 1896,1904 ---- * We do this in two passes: on the first one we collect the list of * plain relations, and on the second one we collect TOAST tables. * The reason for doing the second pass is that during it we want to use ! * the main relation's pg_class.reloptions entry if the TOAST table does ! * not have any, and we cannot obtain it unless we know beforehand what's ! * the main table OID. * * We need to check TOAST tables separately because in cases with short, * wide tables there might be proportionally much more activity in the *************** *** 1923,1932 **** while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) { Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); - Form_pg_autovacuum avForm = NULL; PgStat_StatTabEntry *tabentry; - HeapTuple avTup; Oid relid; bool dovacuum; bool doanalyze; bool wraparound; --- 1918,1927 ---- while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) { Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); PgStat_StatTabEntry *tabentry; Oid relid; + Datum reloptions; + bool isnull; bool dovacuum; bool doanalyze; bool wraparound; *************** *** 1934,1950 **** relid = HeapTupleGetOid(tuple); ! /* Fetch the pg_autovacuum tuple for the relation, if any */ ! avTup = get_pg_autovacuum_tuple_relid(avRel, relid, NULL); ! if (HeapTupleIsValid(avTup)) ! avForm = (Form_pg_autovacuum) GETSTRUCT(avTup); /* Fetch the pgstat entry for this table */ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, shared, dbentry); /* Check if it needs vacuum or analyze */ ! relation_needs_vacanalyze(relid, avForm, classForm, tabentry, &dovacuum, &doanalyze, &wraparound); /* --- 1929,1944 ---- relid = HeapTupleGetOid(tuple); ! /* Fetch reloptions for this table */ ! reloptions = SysCacheGetAttr(RELOID, tuple, ! Anum_pg_class_reloptions, &isnull); /* Fetch the pgstat entry for this table */ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, shared, dbentry); /* Check if it needs vacuum or analyze */ ! relation_needs_vacanalyze(relid, classForm, reloptions, tabentry, &dovacuum, &doanalyze, &wraparound); /* *************** *** 2015,2023 **** } } } - - if (HeapTupleIsValid(avTup)) - heap_freetuple(avTup); } heap_endscan(relScan); --- 2009,2014 ---- *************** *** 2032,2041 **** while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) { Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); - Form_pg_autovacuum avForm = NULL; PgStat_StatTabEntry *tabentry; - HeapTuple avTup; Oid relid; bool dovacuum; bool doanalyze; bool wraparound; --- 2023,2032 ---- while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) { Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); PgStat_StatTabEntry *tabentry; Oid relid; + Datum reloptions; + bool isnull; bool dovacuum; bool doanalyze; bool wraparound; *************** *** 2049,2065 **** relid = HeapTupleGetOid(tuple); ! /* Fetch the pg_autovacuum tuple for this rel */ ! avTup = get_pg_autovacuum_tuple_relid(avRel, relid, table_toast_map); ! if (HeapTupleIsValid(avTup)) ! avForm = (Form_pg_autovacuum) GETSTRUCT(avTup); /* Fetch the pgstat entry for this table */ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, shared, dbentry); ! relation_needs_vacanalyze(relid, avForm, classForm, tabentry, &dovacuum, &doanalyze, &wraparound); /* ignore analyze for toast tables */ --- 2040,2074 ---- relid = HeapTupleGetOid(tuple); ! /* Fetch reloptions for the TOAST table */ ! reloptions = SysCacheGetAttr(RELOID, tuple, ! Anum_pg_class_reloptions, &isnull); ! /* If we don't find, try to get the main table reloptions */ ! if (isnull && table_toast_map != NULL) ! { ! av_relation *hentry; ! bool found; ! ! hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found); ! if (found) ! { ! HeapTuple ttuple = SearchSysCache(RELOID, ! ObjectIdGetDatum(hentry->ar_relid), ! 0, 0, 0); ! if (HeapTupleIsValid(ttuple)) ! reloptions = SysCacheGetAttr(RELOID, ttuple, ! Anum_pg_class_reloptions, &isnull); ! ! ReleaseSysCache(ttuple); ! } ! } /* Fetch the pgstat entry for this table */ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, shared, dbentry); ! relation_needs_vacanalyze(relid, classForm, reloptions, tabentry, &dovacuum, &doanalyze, &wraparound); /* ignore analyze for toast tables */ *************** *** 2068,2074 **** } heap_endscan(relScan); - heap_close(avRel, AccessShareLock); heap_close(classRel, AccessShareLock); /* --- 2077,2082 ---- *************** *** 2284,2335 **** } /* - * Returns a copy of the pg_autovacuum tuple for the given relid, or NULL if - * there isn't any. avRel is pg_autovacuum, already open and suitably locked. - * - * If table_toast_map is not null, use it to find an alternative OID with which - * to search a pg_autovacuum entry, if the passed relid does not yield one - * directly. - */ - static HeapTuple - get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid, - HTAB *table_toast_map) - { - ScanKeyData entry[1]; - SysScanDesc avScan; - HeapTuple avTup; - - ScanKeyInit(&entry[0], - Anum_pg_autovacuum_vacrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(relid)); - - avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true, - SnapshotNow, 1, entry); - - avTup = systable_getnext(avScan); - - if (HeapTupleIsValid(avTup)) - avTup = heap_copytuple(avTup); - - systable_endscan(avScan); - - if (!HeapTupleIsValid(avTup) && table_toast_map != NULL) - { - av_relation *hentry; - bool found; - - hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found); - if (found) - /* avoid second recursion */ - avTup = get_pg_autovacuum_tuple_relid(avRel, hentry->ar_relid, - NULL); - } - - return avTup; - } - - /* * get_pgstat_tabentry_relid * * Fetch the pgstat entry of a table, either local to a database or shared. --- 2292,2297 ---- *************** *** 2364,2374 **** static autovac_table * table_recheck_autovac(Oid relid, HTAB *table_toast_map) { - Form_pg_autovacuum avForm = NULL; Form_pg_class classForm; HeapTuple classTup; - HeapTuple avTup; - Relation avRel; bool dovacuum; bool doanalyze; autovac_table *tab = NULL; --- 2326,2333 ---- *************** *** 2376,2381 **** --- 2335,2342 ---- PgStat_StatDBEntry *shared; PgStat_StatDBEntry *dbentry; bool wraparound; + Datum reloptions; + bool isnull; /* use fresh stats */ autovac_refresh_stats(); *************** *** 2391,2413 **** return NULL; classForm = (Form_pg_class) GETSTRUCT(classTup); ! /* ! * Fetch the pg_autovacuum entry, if any. For a toast table, also try the ! * main rel's pg_autovacuum entry if there isn't one for the TOAST table ! * itself. ! */ ! avRel = heap_open(AutovacuumRelationId, AccessShareLock); ! avTup = get_pg_autovacuum_tuple_relid(avRel, relid, ! classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL); ! if (HeapTupleIsValid(avTup)) ! avForm = (Form_pg_autovacuum) GETSTRUCT(avTup); /* fetch the pgstat table entry */ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, shared, dbentry); ! relation_needs_vacanalyze(relid, avForm, classForm, tabentry, &dovacuum, &doanalyze, &wraparound); /* ignore ANALYZE for toast tables */ --- 2352,2387 ---- return NULL; classForm = (Form_pg_class) GETSTRUCT(classTup); ! /* Fetch reloptions for this table */ ! reloptions = SysCacheGetAttr(RELOID, classTup, Anum_pg_class_reloptions, &isnull); ! ! /* ! * If it is a TOAST table, try to get the main table reloptions if we don't ! * have one ! */ ! if (classForm->relkind == RELKIND_TOASTVALUE && ! !PointerIsValid(DatumGetPointer(reloptions)) && table_toast_map != NULL) ! { ! av_relation *hentry; ! bool found; ! hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found); ! if (found) ! { ! HeapTuple ttuple = SearchSysCache(RELOID, ! ObjectIdGetDatum(hentry->ar_relid), ! 0, 0, 0); ! if (HeapTupleIsValid(ttuple)) ! reloptions = SysCacheGetAttr(RELOID, ttuple, ! Anum_pg_class_reloptions, &isnull); ! } ! } /* fetch the pgstat table entry */ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, shared, dbentry); ! relation_needs_vacanalyze(relid, classForm, reloptions, tabentry, &dovacuum, &doanalyze, &wraparound); /* ignore ANALYZE for toast tables */ *************** *** 2420,2459 **** int freeze_min_age; int vac_cost_limit; int vac_cost_delay; /* * Calculate the vacuum cost parameters and the minimum freeze age. If ! * there is a tuple in pg_autovacuum, use it; else, use the GUC ! * defaults. Note that the fields may contain "-1" (or indeed any * negative value), which means use the GUC defaults for each setting. * In cost_limit, the value 0 also means to use the value from * elsewhere. */ ! if (avForm != NULL) ! { ! vac_cost_limit = (avForm->vac_cost_limit > 0) ? ! avForm->vac_cost_limit : ! ((autovacuum_vac_cost_limit > 0) ? ! autovacuum_vac_cost_limit : VacuumCostLimit); ! ! vac_cost_delay = (avForm->vac_cost_delay >= 0) ? ! avForm->vac_cost_delay : ((autovacuum_vac_cost_delay >= 0) ? autovacuum_vac_cost_delay : VacuumCostDelay); ! freeze_min_age = (avForm->freeze_min_age >= 0) ? ! avForm->freeze_min_age : default_freeze_min_age; ! } else - { vac_cost_limit = (autovacuum_vac_cost_limit > 0) ? autovacuum_vac_cost_limit : VacuumCostLimit; ! vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ? ! autovacuum_vac_cost_delay : VacuumCostDelay; ! freeze_min_age = default_freeze_min_age; - } tab = palloc(sizeof(autovac_table)); tab->at_relid = relid; --- 2394,2429 ---- int freeze_min_age; int vac_cost_limit; int vac_cost_delay; + int vcd, vcl, fma; /* * Calculate the vacuum cost parameters and the minimum freeze age. If ! * there is an option in pg_class.reloptions, use it; else, use the ! * GUC defaults. Note that the fields may contain "-1" (or indeed any * negative value), which means use the GUC defaults for each setting. * In cost_limit, the value 0 also means to use the value from * elsewhere. */ ! if (!isnull && getIntRelOption(reloptions, "autovacuum_cost_delay", &vcd)) ! vac_cost_delay = (vcd >= 0) ? vcd : ((autovacuum_vac_cost_delay >= 0) ? autovacuum_vac_cost_delay : VacuumCostDelay); + else + vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ? + autovacuum_vac_cost_delay : VacuumCostDelay; ! if (!isnull && getIntRelOption(reloptions, "autovacuum_cost_limit", &vcl)) ! vac_cost_limit = (vcl > 0) ? vcl : ! ((autovacuum_vac_cost_limit > 0) ? ! autovacuum_vac_cost_limit : VacuumCostLimit); else vac_cost_limit = (autovacuum_vac_cost_limit > 0) ? autovacuum_vac_cost_limit : VacuumCostLimit; ! if (!isnull && getIntRelOption(reloptions, "autovacuum_freeze_min_age", &fma)) ! freeze_min_age = (fma >= 0) ? fma : default_freeze_min_age; ! else freeze_min_age = default_freeze_min_age; tab = palloc(sizeof(autovac_table)); tab->at_relid = relid; *************** *** 2468,2476 **** tab->at_datname = NULL; } - heap_close(avRel, AccessShareLock); - if (HeapTupleIsValid(avTup)) - heap_freetuple(avTup); heap_freetuple(classTup); return tab; --- 2438,2443 ---- *************** *** 2481,2488 **** * * Check whether a relation needs to be vacuumed or analyzed; return each into * "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is ! * being forced because of Xid wraparound. avForm and tabentry can be NULL, ! * classForm shouldn't. * * A table needs to be vacuumed if the number of dead tuples exceeds a * threshold. This threshold is calculated as --- 2448,2455 ---- * * Check whether a relation needs to be vacuumed or analyzed; return each into * "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is ! * being forced because of Xid wraparound. tabentry can be NULL, classForm ! * shouldn't. * * A table needs to be vacuumed if the number of dead tuples exceeds a * threshold. This threshold is calculated as *************** *** 2498,2517 **** * We also force vacuum if the table's relfrozenxid is more than freeze_max_age * transactions back. * ! * A table whose pg_autovacuum.enabled value is false, is automatically ! * skipped (unless we have to vacuum it due to freeze_max_age). Thus ! * autovacuum can be disabled for specific tables. Also, when the stats * collector does not have data about a table, it will be skipped. * ! * A table whose vac_base_thresh value is <0 takes the base value from the * autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor ! * value <0 is substituted with the value of * autovacuum_vacuum_scale_factor GUC variable. Ditto for analyze. */ static void relation_needs_vacanalyze(Oid relid, - Form_pg_autovacuum avForm, Form_pg_class classForm, PgStat_StatTabEntry *tabentry, /* output params below */ bool *dovacuum, --- 2465,2484 ---- * We also force vacuum if the table's relfrozenxid is more than freeze_max_age * transactions back. * ! * A table whose autovacuum_enabled option at pg_class.reloptions is false, is ! * automatically skipped (unless we have to vacuum it due to freeze_max_age). ! * Thus autovacuum can be disabled for specific tables. Also, when the stats * collector does not have data about a table, it will be skipped. * ! * A table whose vac_base_thresh value is < 0 takes the base value from the * autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor ! * value < 0 is substituted with the value of * autovacuum_vacuum_scale_factor GUC variable. Ditto for analyze. */ static void relation_needs_vacanalyze(Oid relid, Form_pg_class classForm, + Datum reloptions, PgStat_StatTabEntry *tabentry, /* output params below */ bool *dovacuum, *************** *** 2521,2527 **** bool force_vacuum; float4 reltuples; /* pg_class.reltuples */ ! /* constants from pg_autovacuum or GUC variables */ int vac_base_thresh, anl_base_thresh; float4 vac_scale_factor, --- 2488,2494 ---- bool force_vacuum; float4 reltuples; /* pg_class.reltuples */ ! /* constants from pg_class.reloptions parameters or GUC variables */ int vac_base_thresh, anl_base_thresh; float4 vac_scale_factor, *************** *** 2539,2579 **** int freeze_max_age; TransactionId xidForceLimit; AssertArg(classForm != NULL); AssertArg(OidIsValid(relid)); /* ! * Determine vacuum/analyze equation parameters. If there is a tuple in ! * pg_autovacuum, use it; else, use the GUC defaults. Note that the * fields may contain "-1" (or indeed any negative value), which means use * the GUC defaults for each setting. */ ! if (avForm != NULL) ! { ! vac_scale_factor = (avForm->vac_scale_factor >= 0) ? ! avForm->vac_scale_factor : autovacuum_vac_scale; ! vac_base_thresh = (avForm->vac_base_thresh >= 0) ? ! avForm->vac_base_thresh : autovacuum_vac_thresh; ! ! anl_scale_factor = (avForm->anl_scale_factor >= 0) ? ! avForm->anl_scale_factor : autovacuum_anl_scale; ! anl_base_thresh = (avForm->anl_base_thresh >= 0) ? ! avForm->anl_base_thresh : autovacuum_anl_thresh; ! ! freeze_max_age = (avForm->freeze_max_age >= 0) ? ! Min(avForm->freeze_max_age, autovacuum_freeze_max_age) : ! autovacuum_freeze_max_age; ! } else - { vac_scale_factor = autovacuum_vac_scale; vac_base_thresh = autovacuum_vac_thresh; anl_scale_factor = autovacuum_anl_scale; anl_base_thresh = autovacuum_anl_thresh; freeze_max_age = autovacuum_freeze_max_age; - } /* Force vacuum if table is at risk of wraparound */ xidForceLimit = recentXid - freeze_max_age; --- 2506,2549 ---- int freeze_max_age; TransactionId xidForceLimit; + double vsf, asf; + int vbt, abt, fma; + bool av_enabled; + AssertArg(classForm != NULL); AssertArg(OidIsValid(relid)); /* ! * Determine vacuum/analyze equation parameters. If there is an option in ! * pg_class.reloptions, use it; else, use the GUC defaults. Note that the * fields may contain "-1" (or indeed any negative value), which means use * the GUC defaults for each setting. */ ! if (getDoubleRelOption(reloptions, "autovacuum_vac_scale_factor", &vsf)) ! vac_scale_factor = (vsf >= 0) ? vsf : autovacuum_vac_scale; else vac_scale_factor = autovacuum_vac_scale; + + if (getIntRelOption(reloptions, "autovacuum_vac_threshold", &vbt)) + vac_base_thresh = (vbt >= 0) ? vbt : autovacuum_vac_thresh; + else vac_base_thresh = autovacuum_vac_thresh; + if (getDoubleRelOption(reloptions, "autovacuum_anl_scale_factor", &asf)) + anl_scale_factor = (asf >= 0) ? asf : autovacuum_anl_scale; + else anl_scale_factor = autovacuum_anl_scale; + + if (getIntRelOption(reloptions, "autovacuum_anl_threshold", &abt)) + anl_base_thresh = (abt >= 0) ? abt : autovacuum_anl_thresh; + else anl_base_thresh = autovacuum_anl_thresh; + if (getIntRelOption(reloptions, "autovacuum_freeze_max_age", &fma)) + freeze_max_age = (fma >= 0) ? + Min(fma, autovacuum_freeze_max_age) : autovacuum_freeze_max_age; + else freeze_max_age = autovacuum_freeze_max_age; /* Force vacuum if table is at risk of wraparound */ xidForceLimit = recentXid - freeze_max_age; *************** *** 2584,2594 **** xidForceLimit)); *wraparound = force_vacuum; ! /* User disabled it in pg_autovacuum? (But ignore if at risk) */ ! if (avForm && !avForm->enabled && !force_vacuum) { *doanalyze = false; *dovacuum = false; return; } --- 2554,2566 ---- xidForceLimit)); *wraparound = force_vacuum; ! /* User disabled it in pg_class.reloptions? (But ignore if at risk) */ ! if (reloptions && getBoolRelOption(reloptions, "autovacuum_enabled", &av_enabled) && ! !av_enabled && !force_vacuum) { *doanalyze = false; *dovacuum = false; + return; } Index: src/backend/utils/cache/relcache.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/utils/cache/relcache.c,v retrieving revision 1.278 diff -c -r1.278 relcache.c *** src/backend/utils/cache/relcache.c 3 Dec 2008 13:05:22 -0000 1.278 --- src/backend/utils/cache/relcache.c 3 Dec 2008 17:22:23 -0000 *************** *** 387,398 **** case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_UNCATALOGED: ! options = heap_reloptions(relation->rd_rel->relkind, datum, ! false); break; case RELKIND_INDEX: ! options = index_reloptions(relation->rd_am->amoptions, datum, ! false); break; default: Assert(false); /* can't get here */ --- 387,396 ---- case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_UNCATALOGED: ! options = heapRelOptions(datum, false); break; case RELKIND_INDEX: ! options = indexRelOptions(relation->rd_am->amoptions, datum, false); break; default: Assert(false); /* can't get here */ *************** *** 403,411 **** --- 401,421 ---- /* Copy parsed data into CacheMemoryContext */ if (options) { + int ffactor; + relation->rd_options = MemoryContextAlloc(CacheMemoryContext, VARSIZE(options)); memcpy(relation->rd_options, options, VARSIZE(options)); + + /* + * Store fillfactor in another field in RelationData too + * That's because RelationGetXXX() (rel.h) needs fast + * access to it. + */ + if (getIntRelOption(PointerGetDatum(options), "fillfactor", &ffactor)) + relation->fillfactor = ffactor; + else + relation->fillfactor = 0; /* means use the default */ } } Index: src/bin/psql/describe.c =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/bin/psql/describe.c,v retrieving revision 1.188 diff -c -r1.188 describe.c *** src/bin/psql/describe.c 9 Nov 2008 21:24:33 -0000 1.188 --- src/bin/psql/describe.c 29 Nov 2008 17:13:33 -0000 *************** *** 1586,1591 **** --- 1586,1609 ---- printfPQExpBuffer(&buf, "%s: %s", s, (tableinfo.hasoids ? _("yes") : _("no"))); printTableAddFooter(&cont, buf.data); + + /* print reloptions */ + if (pset.sversion >= 80200) + { + printfPQExpBuffer(&buf, "SELECT pg_catalog.array_to_string(reloptions, E'\\n') as relopts FROM pg_catalog.pg_class WHERE oid = '%s'", oid); + result = PSQLexec(buf.data, false); + + if (result) + { + if (PQntuples(result) > 0 && !PQgetisnull(result, 0, 0)) + { + const char *t = _("Options"); + + printfPQExpBuffer(&buf, "%s:\n%s", t, PQgetvalue(result, 0, 0)); + printTableAddFooter(&cont, buf.data); + } + } + } } add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace, Index: src/include/access/gin.h =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/access/gin.h,v retrieving revision 1.26 diff -c -r1.26 gin.h *** src/include/access/gin.h 3 Nov 2008 20:47:49 -0000 1.26 --- src/include/access/gin.h 29 Nov 2008 17:13:33 -0000 *************** *** 235,240 **** --- 235,248 ---- } ginxlogDeletePage; /* ginutil.c */ + + /* + * It's not clear that fillfactor is useful for GIN, but for the moment + * we'll accept it anyway. It won't do anything! + */ + #define GIN_MIN_FILLFACTOR 10 + #define GIN_DEFAULT_FILLFACTOR 100 + extern Datum ginoptions(PG_FUNCTION_ARGS); extern void initGinState(GinState *state, Relation index); extern Buffer GinNewBuffer(Relation index); Index: src/include/access/reloptions.h =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/access/reloptions.h,v retrieving revision 1.5 diff -c -r1.5 reloptions.h *** src/include/access/reloptions.h 1 Jan 2008 19:45:56 -0000 1.5 --- src/include/access/reloptions.h 1 Dec 2008 22:54:53 -0000 *************** *** 20,40 **** #include "nodes/pg_list.h" ! extern Datum transformRelOptions(Datum oldOptions, List *defList, ! bool ignoreOids, bool isReset); extern List *untransformRelOptions(Datum options); ! extern void parseRelOptions(Datum options, int numkeywords, ! const char *const * keywords, ! char **values, bool validate); ! ! extern bytea *default_reloptions(Datum reloptions, bool validate, ! int minFillfactor, int defaultFillfactor); ! ! extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate); ! ! extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions, ! bool validate); #endif /* RELOPTIONS_H */ --- 20,84 ---- #include "nodes/pg_list.h" ! /* types supported by reloptions */ ! enum relopt_type ! { ! RELOPT_TYPE_BOOL, ! RELOPT_TYPE_INT, ! RELOPT_TYPE_REAL ! }; ! ! /* kind supported by reloptions */ ! #define RELOPT_KIND_NULL (1 << 0) ! #define RELOPT_KIND_HEAP (1 << 1) ! #define RELOPT_KIND_INDEX (1 << 2) ! ! /* generic struct to hold shared data */ ! struct relopt_gen ! { ! const char *name; ! const char *desc; ! enum relopt_type type; /* type of variable */ ! uint16 kind; /* index or heap? see definition above */ ! }; ! ! ! /* reloptions records for specific variable types */ ! struct relopt_bool ! { ! struct relopt_gen gen; ! bool value; ! }; ! ! struct relopt_int ! { ! struct relopt_gen gen; ! int value; ! int min; ! int max; ! }; ! ! struct relopt_real ! { ! struct relopt_gen gen; ! double value; ! double min; ! double max; ! }; + extern Datum transformRelOptions(Datum oldOptions, List *defList, + bool ignoreOids, bool isReset); extern List *untransformRelOptions(Datum options); ! extern bool getCharRelOption(Datum options, char *opt, char *result); ! extern bool getBoolRelOption(Datum options, char *opt, bool *result); ! extern bool getIntRelOption(Datum options, char *opt, int *result); ! extern bool getDoubleRelOption(Datum options, char *opt, double *result); ! ! extern bytea *defaultRelOptions(Datum reloptions, bool validate, ! int minFillFactor, uint16 reloptkind); ! extern bytea *heapRelOptions(Datum reloptions, bool validate); ! extern bytea *indexRelOptions(RegProcedure amoptions, Datum reloptions, ! bool validate); #endif /* RELOPTIONS_H */ Index: src/include/catalog/indexing.h =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/catalog/indexing.h,v retrieving revision 1.103 diff -c -r1.103 indexing.h *** src/include/catalog/indexing.h 19 Jun 2008 00:46:06 -0000 1.103 --- src/include/catalog/indexing.h 29 Nov 2008 17:13:33 -0000 *************** *** 97,105 **** DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index, 2695, on pg_auth_members using btree(member oid_ops, roleid oid_ops)); #define AuthMemMemRoleIndexId 2695 - DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index, 1250, on pg_autovacuum using btree(vacrelid oid_ops)); - #define AutovacuumRelidIndexId 1250 - DECLARE_UNIQUE_INDEX(pg_cast_oid_index, 2660, on pg_cast using btree(oid oid_ops)); #define CastOidIndexId 2660 DECLARE_UNIQUE_INDEX(pg_cast_source_target_index, 2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops)); --- 97,102 ---- Index: src/include/catalog/pg_class.h =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/catalog/pg_class.h,v retrieving revision 1.109 diff -c -r1.109 pg_class.h *** src/include/catalog/pg_class.h 4 Dec 2008 17:51:27 -0000 1.109 --- src/include/catalog/pg_class.h 4 Dec 2008 20:50:30 -0000 *************** *** 66,72 **** */ aclitem relacl[1]; /* access permissions */ ! text reloptions[1]; /* access-method-specific options */ } FormData_pg_class; /* Size of fixed part of pg_class tuples, not counting var-length fields */ --- 66,72 ---- */ aclitem relacl[1]; /* access permissions */ ! text reloptions[1]; /* relation-specific options */ } FormData_pg_class; /* Size of fixed part of pg_class tuples, not counting var-length fields */ Index: src/include/utils/rel.h =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/utils/rel.h,v retrieving revision 1.110 diff -c -r1.110 rel.h *** src/include/utils/rel.h 3 Dec 2008 13:05:22 -0000 1.110 --- src/include/utils/rel.h 3 Dec 2008 16:54:33 -0000 *************** *** 162,167 **** --- 162,174 ---- */ bytea *rd_options; /* parsed pg_class.reloptions */ + /* + * fillfactor is stored outside rd_options too. That's because we don't want + * to find out (in rd_options) what is its value every time we call + * RelationGetFillFactor() or RelationGetTargetPageFreeSpace(). + */ + int fillfactor; /* page fill factor in percentage (0..100) */ + /* These are non-NULL only for an index relation: */ Form_pg_index rd_index; /* pg_index tuple describing this index */ struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ *************** *** 206,225 **** struct PgStat_TableStatus *pgstat_info; /* statistics collection area */ } RelationData; - /* - * StdRdOptions - * Standard contents of rd_options for heaps and generic indexes. - * - * RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only - * be applied to relations that use this format or a superset for - * private options data. - */ - typedef struct StdRdOptions - { - int32 vl_len_; /* varlena header (do not touch directly!) */ - int fillfactor; /* page fill factor in percent (0..100) */ - } StdRdOptions; - #define HEAP_MIN_FILLFACTOR 10 #define HEAP_DEFAULT_FILLFACTOR 100 --- 213,218 ---- *************** *** 228,235 **** * Returns the relation's fillfactor. Note multiple eval of argument! */ #define RelationGetFillFactor(relation, defaultff) \ ! ((relation)->rd_options ? \ ! ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff)) /* * RelationGetTargetPageUsage --- 221,228 ---- * Returns the relation's fillfactor. Note multiple eval of argument! */ #define RelationGetFillFactor(relation, defaultff) \ ! (((relation)->fillfactor > 0) ? \ ! (relation)->fillfactor : (defaultff)) /* * RelationGetTargetPageUsage Index: src/test/regress/expected/sanity_check.out =================================================================== RCS file: /a/pgsql/dev/anoncvs/pgsql/src/test/regress/expected/sanity_check.out,v retrieving revision 1.37 diff -c -r1.37 sanity_check.out *** src/test/regress/expected/sanity_check.out 24 Nov 2007 19:49:23 -0000 1.37 --- src/test/regress/expected/sanity_check.out 5 Dec 2008 04:00:06 -0000 *************** *** 90,96 **** pg_attribute | t pg_auth_members | t pg_authid | t - pg_autovacuum | t pg_cast | t pg_class | t pg_constraint | t --- 90,95 ---- *************** *** 149,155 **** timetz_tbl | f tinterval_tbl | f varchar_tbl | f ! (138 rows) -- -- another sanity check: every system catalog that has OIDs should have --- 148,154 ---- timetz_tbl | f tinterval_tbl | f varchar_tbl | f ! (137 rows) -- -- another sanity check: every system catalog that has OIDs should have