Custom reloptions for table AM
Let table AM define custom reloptions for its tables. This allows specifying AM-specific parameters by the WITH clause when creating a table. The reloptions, which could be used outside of table AM, are now extracted into the CommonRdOptions data structure. These options could be by decision of table AM directly specified by a user or calculated in some way. The new test module test_tam_options evaluates the ability to set up custom reloptions and calculate fields of CommonRdOptions on their base. The code may use some parts from prior work by Hao Wu. Discussion: https://postgr.es/m/CAPpHfdurb9ycV8udYqM%3Do0sPS66PJ4RCBM1g-bBpvzUfogY0EA%40mail.gmail.com Discussion: https://postgr.es/m/AMUA1wBBBxfc3tKRLLdU64rb.1.1683276279979.Hmail.wuhao%40hashdata.cn Reviewed-by: Reviewed-by: Pavel Borisov, Matthias van de Meent, Jess Davis
This commit is contained in:
parent
6f3d8d5e7c
commit
9bd99f4c26
|
@ -24,6 +24,7 @@
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "access/reloptions.h"
|
#include "access/reloptions.h"
|
||||||
#include "access/spgist_private.h"
|
#include "access/spgist_private.h"
|
||||||
|
#include "access/tableam.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/tablespace.h"
|
#include "commands/tablespace.h"
|
||||||
|
@ -44,7 +45,7 @@
|
||||||
* value, upper and lower bounds (if applicable); for strings, consider a
|
* value, upper and lower bounds (if applicable); for strings, consider a
|
||||||
* validation routine.
|
* validation routine.
|
||||||
* (ii) add a record below (or use add_<type>_reloption).
|
* (ii) add a record below (or use add_<type>_reloption).
|
||||||
* (iii) add it to the appropriate options struct (perhaps StdRdOptions)
|
* (iii) add it to the appropriate options struct (perhaps HeapRdOptions)
|
||||||
* (iv) add it to the appropriate handling routine (perhaps
|
* (iv) add it to the appropriate handling routine (perhaps
|
||||||
* default_reloptions)
|
* default_reloptions)
|
||||||
* (v) make sure the lock level is set correctly for that operation
|
* (v) make sure the lock level is set correctly for that operation
|
||||||
|
@ -1374,10 +1375,16 @@ untransformRelOptions(Datum options)
|
||||||
* tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
|
* tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
|
||||||
* AM's options parser function in the case of a tuple corresponding to an
|
* AM's options parser function in the case of a tuple corresponding to an
|
||||||
* index, or NULL otherwise.
|
* index, or NULL otherwise.
|
||||||
|
*
|
||||||
|
* If common pointer is provided, then the corresponding struct will be
|
||||||
|
* filled with options that table AM exposes for external usage. That must
|
||||||
|
* be filled with defaults before passing here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bytea *
|
bytea *
|
||||||
extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
|
extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
|
||||||
amoptions_function amoptions)
|
const TableAmRoutine *tableam, amoptions_function amoptions,
|
||||||
|
CommonRdOptions *common)
|
||||||
{
|
{
|
||||||
bytea *options;
|
bytea *options;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
@ -1399,7 +1406,8 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
|
||||||
case RELKIND_RELATION:
|
case RELKIND_RELATION:
|
||||||
case RELKIND_TOASTVALUE:
|
case RELKIND_TOASTVALUE:
|
||||||
case RELKIND_MATVIEW:
|
case RELKIND_MATVIEW:
|
||||||
options = heap_reloptions(classForm->relkind, datum, false);
|
options = tableam_reloptions(tableam, classForm->relkind,
|
||||||
|
datum, common, false);
|
||||||
break;
|
break;
|
||||||
case RELKIND_PARTITIONED_TABLE:
|
case RELKIND_PARTITIONED_TABLE:
|
||||||
options = partitioned_table_reloptions(datum, false);
|
options = partitioned_table_reloptions(datum, false);
|
||||||
|
@ -1695,7 +1703,7 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
|
||||||
* Given the result from parseRelOptions, allocate a struct that's of the
|
* Given the result from parseRelOptions, allocate a struct that's of the
|
||||||
* specified base size plus any extra space that's needed for string variables.
|
* specified base size plus any extra space that's needed for string variables.
|
||||||
*
|
*
|
||||||
* "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
|
* "base" should be sizeof(struct) of the reloptions struct (HeapRdOptions or
|
||||||
* equivalent).
|
* equivalent).
|
||||||
*/
|
*/
|
||||||
static void *
|
static void *
|
||||||
|
@ -1832,59 +1840,95 @@ fillRelOptions(void *rdopts, Size basesize,
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Option parser for anything that uses StdRdOptions.
|
* Option parser for anything that uses HeapRdOptions.
|
||||||
*/
|
*/
|
||||||
bytea *
|
static bytea *
|
||||||
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
|
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
|
||||||
{
|
{
|
||||||
static const relopt_parse_elt tab[] = {
|
static const relopt_parse_elt tab[] = {
|
||||||
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
|
{"fillfactor", RELOPT_TYPE_INT, offsetof(HeapRdOptions, fillfactor)},
|
||||||
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
|
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, enabled)},
|
||||||
{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
|
{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, vacuum_threshold)},
|
||||||
{"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
|
{"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, vacuum_ins_threshold)},
|
||||||
{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
|
{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, analyze_threshold)},
|
||||||
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
|
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, vacuum_cost_limit)},
|
||||||
{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
|
{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, freeze_min_age)},
|
||||||
{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
|
{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, freeze_max_age)},
|
||||||
{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
|
{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, freeze_table_age)},
|
||||||
{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
|
{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, multixact_freeze_min_age)},
|
||||||
{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
|
{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, multixact_freeze_max_age)},
|
||||||
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
|
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, multixact_freeze_table_age)},
|
||||||
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
|
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, log_min_duration)},
|
||||||
{"toast_tuple_target", RELOPT_TYPE_INT,
|
{"toast_tuple_target", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, toast_tuple_target)},
|
offsetof(HeapRdOptions, toast_tuple_target)},
|
||||||
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
|
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, vacuum_cost_delay)},
|
||||||
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
|
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, vacuum_scale_factor)},
|
||||||
{"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
|
{"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
|
||||||
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
|
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
|
||||||
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, autovacuum) +
|
||||||
|
offsetof(AutoVacOpts, analyze_scale_factor)},
|
||||||
{"user_catalog_table", RELOPT_TYPE_BOOL,
|
{"user_catalog_table", RELOPT_TYPE_BOOL,
|
||||||
offsetof(StdRdOptions, user_catalog_table)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, user_catalog_table)},
|
||||||
{"parallel_workers", RELOPT_TYPE_INT,
|
{"parallel_workers", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, parallel_workers)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, parallel_workers)},
|
||||||
{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
|
{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
|
||||||
offsetof(StdRdOptions, vacuum_index_cleanup)},
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, vacuum_index_cleanup)},
|
||||||
{"vacuum_truncate", RELOPT_TYPE_BOOL,
|
{"vacuum_truncate", RELOPT_TYPE_BOOL,
|
||||||
offsetof(StdRdOptions, vacuum_truncate)}
|
offsetof(HeapRdOptions, common) +
|
||||||
|
offsetof(CommonRdOptions, vacuum_truncate)}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (bytea *) build_reloptions(reloptions, validate, kind,
|
return (bytea *) build_reloptions(reloptions, validate, kind,
|
||||||
sizeof(StdRdOptions),
|
sizeof(HeapRdOptions),
|
||||||
tab, lengthof(tab));
|
tab, lengthof(tab));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2016,26 +2060,33 @@ view_reloptions(Datum reloptions, bool validate)
|
||||||
* Parse options for heaps, views and toast tables.
|
* Parse options for heaps, views and toast tables.
|
||||||
*/
|
*/
|
||||||
bytea *
|
bytea *
|
||||||
heap_reloptions(char relkind, Datum reloptions, bool validate)
|
heap_reloptions(char relkind, Datum reloptions,
|
||||||
|
CommonRdOptions *common, bool validate)
|
||||||
{
|
{
|
||||||
StdRdOptions *rdopts;
|
HeapRdOptions *rdopts;
|
||||||
|
|
||||||
switch (relkind)
|
switch (relkind)
|
||||||
{
|
{
|
||||||
case RELKIND_TOASTVALUE:
|
case RELKIND_TOASTVALUE:
|
||||||
rdopts = (StdRdOptions *)
|
rdopts = (HeapRdOptions *)
|
||||||
default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
|
default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
|
||||||
if (rdopts != NULL)
|
if (rdopts != NULL)
|
||||||
{
|
{
|
||||||
/* adjust default-only parameters for TOAST relations */
|
/* adjust default-only parameters for TOAST relations */
|
||||||
rdopts->fillfactor = 100;
|
rdopts->fillfactor = 100;
|
||||||
rdopts->autovacuum.analyze_threshold = -1;
|
rdopts->common.autovacuum.analyze_threshold = -1;
|
||||||
rdopts->autovacuum.analyze_scale_factor = -1;
|
rdopts->common.autovacuum.analyze_scale_factor = -1;
|
||||||
}
|
}
|
||||||
|
if (rdopts != NULL && common != NULL)
|
||||||
|
*common = rdopts->common;
|
||||||
return (bytea *) rdopts;
|
return (bytea *) rdopts;
|
||||||
case RELKIND_RELATION:
|
case RELKIND_RELATION:
|
||||||
case RELKIND_MATVIEW:
|
case RELKIND_MATVIEW:
|
||||||
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
|
rdopts = (HeapRdOptions *)
|
||||||
|
default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
|
||||||
|
if (rdopts != NULL && common != NULL)
|
||||||
|
*common = rdopts->common;
|
||||||
|
return (bytea *) rdopts;
|
||||||
default:
|
default:
|
||||||
/* other relkinds are not supported */
|
/* other relkinds are not supported */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -2279,8 +2279,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
|
||||||
Assert(!(options & HEAP_INSERT_NO_LOGICAL));
|
Assert(!(options & HEAP_INSERT_NO_LOGICAL));
|
||||||
|
|
||||||
needwal = RelationNeedsWAL(relation);
|
needwal = RelationNeedsWAL(relation);
|
||||||
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
|
saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
|
||||||
HEAP_DEFAULT_FILLFACTOR);
|
HEAP_DEFAULT_FILLFACTOR);
|
||||||
|
|
||||||
/* Toast and set header data in all the slots */
|
/* Toast and set header data in all the slots */
|
||||||
heaptuples = palloc(ntuples * sizeof(HeapTuple));
|
heaptuples = palloc(ntuples * sizeof(HeapTuple));
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/heaptoast.h"
|
#include "access/heaptoast.h"
|
||||||
#include "access/multixact.h"
|
#include "access/multixact.h"
|
||||||
|
#include "access/reloptions.h"
|
||||||
#include "access/rewriteheap.h"
|
#include "access/rewriteheap.h"
|
||||||
#include "access/syncscan.h"
|
#include "access/syncscan.h"
|
||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
|
@ -2161,6 +2162,17 @@ heapam_relation_toast_am(Relation rel)
|
||||||
return rel->rd_rel->relam;
|
return rel->rd_rel->relam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bytea *
|
||||||
|
heapam_reloptions(char relkind, Datum reloptions,
|
||||||
|
CommonRdOptions *common, bool validate)
|
||||||
|
{
|
||||||
|
Assert(relkind == RELKIND_RELATION ||
|
||||||
|
relkind == RELKIND_TOASTVALUE ||
|
||||||
|
relkind == RELKIND_MATVIEW);
|
||||||
|
|
||||||
|
return heap_reloptions(relkind, reloptions, common, validate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------
|
||||||
* Planner related callbacks for the heap AM
|
* Planner related callbacks for the heap AM
|
||||||
|
@ -2710,6 +2722,7 @@ static const TableAmRoutine heapam_methods = {
|
||||||
.relation_needs_toast_table = heapam_relation_needs_toast_table,
|
.relation_needs_toast_table = heapam_relation_needs_toast_table,
|
||||||
.relation_toast_am = heapam_relation_toast_am,
|
.relation_toast_am = heapam_relation_toast_am,
|
||||||
.relation_fetch_toast_slice = heap_fetch_toast_slice,
|
.relation_fetch_toast_slice = heap_fetch_toast_slice,
|
||||||
|
.reloptions = heapam_reloptions,
|
||||||
|
|
||||||
.relation_estimate_size = heapam_estimate_rel_size,
|
.relation_estimate_size = heapam_estimate_rel_size,
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
#include "access/toast_internals.h"
|
#include "access/toast_internals.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HeapGetToastTupleTarget
|
||||||
|
* Returns the heap relation's toast_tuple_target. Note multiple eval of argument!
|
||||||
|
*/
|
||||||
|
#define HeapGetToastTupleTarget(relation, defaulttarg) \
|
||||||
|
((HeapRdOptions *) (relation)->rd_options ? \
|
||||||
|
((HeapRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* heap_toast_delete -
|
* heap_toast_delete -
|
||||||
|
@ -174,7 +181,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
|
||||||
hoff += BITMAPLEN(numAttrs);
|
hoff += BITMAPLEN(numAttrs);
|
||||||
hoff = MAXALIGN(hoff);
|
hoff = MAXALIGN(hoff);
|
||||||
/* now convert to a limit on the tuple data size */
|
/* now convert to a limit on the tuple data size */
|
||||||
maxDataLen = RelationGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
|
maxDataLen = HeapGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for attributes with attstorage EXTENDED to compress. Also find
|
* Look for attributes with attstorage EXTENDED to compress. Also find
|
||||||
|
|
|
@ -536,8 +536,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
len, MaxHeapTupleSize)));
|
len, MaxHeapTupleSize)));
|
||||||
|
|
||||||
/* Compute desired extra freespace due to fillfactor option */
|
/* Compute desired extra freespace due to fillfactor option */
|
||||||
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
|
saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
|
||||||
HEAP_DEFAULT_FILLFACTOR);
|
HEAP_DEFAULT_FILLFACTOR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since pages without tuples can still have line pointers, we consider
|
* Since pages without tuples can still have line pointers, we consider
|
||||||
|
|
|
@ -235,8 +235,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
|
||||||
* important than sometimes getting a wrong answer in what is after all
|
* important than sometimes getting a wrong answer in what is after all
|
||||||
* just a heuristic estimate.
|
* just a heuristic estimate.
|
||||||
*/
|
*/
|
||||||
minfree = RelationGetTargetPageFreeSpace(relation,
|
minfree = HeapGetTargetPageFreeSpace(relation,
|
||||||
HEAP_DEFAULT_FILLFACTOR);
|
HEAP_DEFAULT_FILLFACTOR);
|
||||||
minfree = Max(minfree, BLCKSZ / 10);
|
minfree = Max(minfree, BLCKSZ / 10);
|
||||||
|
|
||||||
if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
|
if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
|
||||||
|
|
|
@ -641,8 +641,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
|
||||||
len, MaxHeapTupleSize)));
|
len, MaxHeapTupleSize)));
|
||||||
|
|
||||||
/* Compute desired extra freespace due to fillfactor option */
|
/* Compute desired extra freespace due to fillfactor option */
|
||||||
saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel,
|
saveFreeSpace = HeapGetTargetPageFreeSpace(state->rs_new_rel,
|
||||||
HEAP_DEFAULT_FILLFACTOR);
|
HEAP_DEFAULT_FILLFACTOR);
|
||||||
|
|
||||||
/* Now we can check to see if there's enough free space already. */
|
/* Now we can check to see if there's enough free space already. */
|
||||||
page = (Page) state->rs_buffer;
|
page = (Page) state->rs_buffer;
|
||||||
|
|
|
@ -750,7 +750,7 @@ table_block_relation_estimate_size(Relation rel, int32 *attr_widths,
|
||||||
* The other branch considers it implicitly by calculating density
|
* The other branch considers it implicitly by calculating density
|
||||||
* from actual relpages/reltuples statistics.
|
* from actual relpages/reltuples statistics.
|
||||||
*/
|
*/
|
||||||
fillfactor = RelationGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
|
fillfactor = HeapGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
|
||||||
|
|
||||||
tuple_width = get_rel_data_width(rel, attr_widths);
|
tuple_width = get_rel_data_width(rel, attr_widths);
|
||||||
tuple_width += overhead_bytes_per_tuple;
|
tuple_width += overhead_bytes_per_tuple;
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
|
|
||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
|
#include "catalog/pg_am.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "utils/guc_hooks.h"
|
#include "utils/guc_hooks.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -98,6 +100,29 @@ GetTableAmRoutine(Oid amhandler)
|
||||||
return routine;
|
return routine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetTableAmRoutineByAmOid
|
||||||
|
* Given the table access method oid get its TableAmRoutine struct, which
|
||||||
|
* will be palloc'd in the caller's memory context.
|
||||||
|
*/
|
||||||
|
const TableAmRoutine *
|
||||||
|
GetTableAmRoutineByAmOid(Oid amoid)
|
||||||
|
{
|
||||||
|
HeapTuple ht_am;
|
||||||
|
Form_pg_am amrec;
|
||||||
|
const TableAmRoutine *tableam = NULL;
|
||||||
|
|
||||||
|
ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
|
||||||
|
if (!HeapTupleIsValid(ht_am))
|
||||||
|
elog(ERROR, "cache lookup failed for access method %u",
|
||||||
|
amoid);
|
||||||
|
amrec = (Form_pg_am) GETSTRUCT(ht_am);
|
||||||
|
|
||||||
|
tableam = GetTableAmRoutine(amrec->amhandler);
|
||||||
|
ReleaseSysCache(ht_am);
|
||||||
|
return tableam;
|
||||||
|
}
|
||||||
|
|
||||||
/* check_hook: validate new default_table_access_method */
|
/* check_hook: validate new default_table_access_method */
|
||||||
bool
|
bool
|
||||||
check_default_table_access_method(char **newval, void **extra, GucSource source)
|
check_default_table_access_method(char **newval, void **extra, GucSource source)
|
||||||
|
|
|
@ -85,6 +85,9 @@ create_ctas_internal(List *attrList, IntoClause *into)
|
||||||
Datum toast_options;
|
Datum toast_options;
|
||||||
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
||||||
ObjectAddress intoRelationAddr;
|
ObjectAddress intoRelationAddr;
|
||||||
|
const TableAmRoutine *tableam = NULL;
|
||||||
|
Oid accessMethodId = InvalidOid;
|
||||||
|
Relation rel;
|
||||||
|
|
||||||
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
|
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
|
||||||
is_matview = (into->viewQuery != NULL);
|
is_matview = (into->viewQuery != NULL);
|
||||||
|
@ -125,7 +128,15 @@ create_ctas_internal(List *attrList, IntoClause *into)
|
||||||
validnsps,
|
validnsps,
|
||||||
true, false);
|
true, false);
|
||||||
|
|
||||||
(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
|
rel = relation_open(intoRelationAddr.objectId, AccessShareLock);
|
||||||
|
accessMethodId = table_relation_toast_am(rel);
|
||||||
|
relation_close(rel, AccessShareLock);
|
||||||
|
|
||||||
|
if (OidIsValid(accessMethodId))
|
||||||
|
{
|
||||||
|
tableam = GetTableAmRoutineByAmOid(accessMethodId);
|
||||||
|
(void) tableam_reloptions(tableam, RELKIND_TOASTVALUE, toast_options, NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
|
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
|
||||||
|
|
||||||
|
|
|
@ -720,6 +720,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
|
||||||
ObjectAddress address;
|
ObjectAddress address;
|
||||||
LOCKMODE parentLockmode;
|
LOCKMODE parentLockmode;
|
||||||
Oid accessMethodId = InvalidOid;
|
Oid accessMethodId = InvalidOid;
|
||||||
|
const TableAmRoutine *tableam = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Truncate relname to appropriate length (probably a waste of time, as
|
* Truncate relname to appropriate length (probably a waste of time, as
|
||||||
|
@ -855,6 +856,28 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
|
||||||
if (!OidIsValid(ownerId))
|
if (!OidIsValid(ownerId))
|
||||||
ownerId = GetUserId();
|
ownerId = GetUserId();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For relations with table AM and partitioned tables, select access
|
||||||
|
* method to use: an explicitly indicated one, or (in the case of a
|
||||||
|
* partitioned table) the parent's, if it has one.
|
||||||
|
*/
|
||||||
|
if (stmt->accessMethod != NULL)
|
||||||
|
{
|
||||||
|
Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
|
||||||
|
accessMethodId = get_table_am_oid(stmt->accessMethod, false);
|
||||||
|
}
|
||||||
|
else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
|
||||||
|
{
|
||||||
|
if (stmt->partbound)
|
||||||
|
{
|
||||||
|
Assert(list_length(inheritOids) == 1);
|
||||||
|
accessMethodId = get_rel_relam(linitial_oid(inheritOids));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
|
||||||
|
accessMethodId = get_table_am_oid(default_table_access_method, false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and validate reloptions, if any.
|
* Parse and validate reloptions, if any.
|
||||||
*/
|
*/
|
||||||
|
@ -863,6 +886,12 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
|
||||||
|
|
||||||
switch (relkind)
|
switch (relkind)
|
||||||
{
|
{
|
||||||
|
case RELKIND_RELATION:
|
||||||
|
case RELKIND_TOASTVALUE:
|
||||||
|
case RELKIND_MATVIEW:
|
||||||
|
tableam = GetTableAmRoutineByAmOid(accessMethodId);
|
||||||
|
(void) tableam_reloptions(tableam, relkind, reloptions, NULL, true);
|
||||||
|
break;
|
||||||
case RELKIND_VIEW:
|
case RELKIND_VIEW:
|
||||||
(void) view_reloptions(reloptions, true);
|
(void) view_reloptions(reloptions, true);
|
||||||
break;
|
break;
|
||||||
|
@ -870,7 +899,12 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
|
||||||
(void) partitioned_table_reloptions(reloptions, true);
|
(void) partitioned_table_reloptions(reloptions, true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
(void) heap_reloptions(relkind, reloptions, true);
|
if (OidIsValid(accessMethodId))
|
||||||
|
{
|
||||||
|
tableam = GetTableAmRoutineByAmOid(accessMethodId);
|
||||||
|
(void) tableam_reloptions(tableam, relkind, reloptions, NULL, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->ofTypename)
|
if (stmt->ofTypename)
|
||||||
|
@ -962,28 +996,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For relations with table AM and partitioned tables, select access
|
|
||||||
* method to use: an explicitly indicated one, or (in the case of a
|
|
||||||
* partitioned table) the parent's, if it has one.
|
|
||||||
*/
|
|
||||||
if (stmt->accessMethod != NULL)
|
|
||||||
{
|
|
||||||
Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
|
|
||||||
accessMethodId = get_table_am_oid(stmt->accessMethod, false);
|
|
||||||
}
|
|
||||||
else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
|
|
||||||
{
|
|
||||||
if (stmt->partbound)
|
|
||||||
{
|
|
||||||
Assert(list_length(inheritOids) == 1);
|
|
||||||
accessMethodId = get_rel_relam(linitial_oid(inheritOids));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
|
|
||||||
accessMethodId = get_table_am_oid(default_table_access_method, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the relation. Inherited defaults and constraints are passed in
|
* Create the relation. Inherited defaults and constraints are passed in
|
||||||
* for immediate handling --- since they don't need parsing, they can be
|
* for immediate handling --- since they don't need parsing, they can be
|
||||||
|
@ -15571,7 +15583,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
|
||||||
case RELKIND_RELATION:
|
case RELKIND_RELATION:
|
||||||
case RELKIND_TOASTVALUE:
|
case RELKIND_TOASTVALUE:
|
||||||
case RELKIND_MATVIEW:
|
case RELKIND_MATVIEW:
|
||||||
(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
|
(void) table_reloptions(rel, rel->rd_rel->relkind,
|
||||||
|
newOptions, NULL, true);
|
||||||
break;
|
break;
|
||||||
case RELKIND_PARTITIONED_TABLE:
|
case RELKIND_PARTITIONED_TABLE:
|
||||||
(void) partitioned_table_reloptions(newOptions, true);
|
(void) partitioned_table_reloptions(newOptions, true);
|
||||||
|
@ -15684,7 +15697,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
|
||||||
defList, "toast", validnsps, false,
|
defList, "toast", validnsps, false,
|
||||||
operation == AT_ResetRelOptions);
|
operation == AT_ResetRelOptions);
|
||||||
|
|
||||||
(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
|
(void) table_reloptions(rel, RELKIND_TOASTVALUE, newOptions, NULL, true);
|
||||||
|
|
||||||
memset(repl_val, 0, sizeof(repl_val));
|
memset(repl_val, 0, sizeof(repl_val));
|
||||||
memset(repl_null, false, sizeof(repl_null));
|
memset(repl_null, false, sizeof(repl_null));
|
||||||
|
|
|
@ -2121,11 +2121,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
|
||||||
{
|
{
|
||||||
StdRdOptIndexCleanup vacuum_index_cleanup;
|
StdRdOptIndexCleanup vacuum_index_cleanup;
|
||||||
|
|
||||||
if (rel->rd_options == NULL)
|
if (rel->rd_common_options == NULL)
|
||||||
vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
|
vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
|
||||||
else
|
else
|
||||||
vacuum_index_cleanup =
|
vacuum_index_cleanup =
|
||||||
((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup;
|
rel->rd_common_options->vacuum_index_cleanup;
|
||||||
|
|
||||||
if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO)
|
if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO)
|
||||||
params->index_cleanup = VACOPTVALUE_AUTO;
|
params->index_cleanup = VACOPTVALUE_AUTO;
|
||||||
|
@ -2145,8 +2145,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
|
||||||
*/
|
*/
|
||||||
if (params->truncate == VACOPTVALUE_UNSPECIFIED)
|
if (params->truncate == VACOPTVALUE_UNSPECIFIED)
|
||||||
{
|
{
|
||||||
if (rel->rd_options == NULL ||
|
if (rel->rd_common_options == NULL ||
|
||||||
((StdRdOptions *) rel->rd_options)->vacuum_truncate)
|
rel->rd_common_options->vacuum_truncate)
|
||||||
params->truncate = VACOPTVALUE_ENABLED;
|
params->truncate = VACOPTVALUE_ENABLED;
|
||||||
else
|
else
|
||||||
params->truncate = VACOPTVALUE_DISABLED;
|
params->truncate = VACOPTVALUE_DISABLED;
|
||||||
|
|
|
@ -2674,19 +2674,21 @@ static AutoVacOpts *
|
||||||
extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
|
extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
|
||||||
{
|
{
|
||||||
bytea *relopts;
|
bytea *relopts;
|
||||||
|
CommonRdOptions common;
|
||||||
AutoVacOpts *av;
|
AutoVacOpts *av;
|
||||||
|
|
||||||
Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
|
Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
|
||||||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
|
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
|
||||||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
|
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
|
||||||
|
|
||||||
relopts = extractRelOptions(tup, pg_class_desc, NULL);
|
relopts = extractRelOptions(tup, pg_class_desc,
|
||||||
if (relopts == NULL)
|
GetTableAmRoutineByAmOid(((Form_pg_class) GETSTRUCT(tup))->relam),
|
||||||
return NULL;
|
NULL, &common);
|
||||||
|
if (relopts)
|
||||||
|
pfree(relopts);
|
||||||
|
|
||||||
av = palloc(sizeof(AutoVacOpts));
|
av = palloc(sizeof(AutoVacOpts));
|
||||||
memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
|
memcpy(av, &(common.autovacuum), sizeof(AutoVacOpts));
|
||||||
pfree(relopts);
|
|
||||||
|
|
||||||
return av;
|
return av;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "access/relation.h"
|
||||||
|
|
||||||
/* Hook for plugins to get control in ProcessUtility() */
|
/* Hook for plugins to get control in ProcessUtility() */
|
||||||
ProcessUtility_hook_type ProcessUtility_hook = NULL;
|
ProcessUtility_hook_type ProcessUtility_hook = NULL;
|
||||||
|
@ -1156,6 +1157,9 @@ ProcessUtilitySlow(ParseState *pstate,
|
||||||
CreateStmt *cstmt = (CreateStmt *) stmt;
|
CreateStmt *cstmt = (CreateStmt *) stmt;
|
||||||
Datum toast_options;
|
Datum toast_options;
|
||||||
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
|
||||||
|
const TableAmRoutine *tableam = NULL;
|
||||||
|
Oid accessMethodId;
|
||||||
|
Relation rel;
|
||||||
|
|
||||||
/* Remember transformed RangeVar for LIKE */
|
/* Remember transformed RangeVar for LIKE */
|
||||||
table_rv = cstmt->relation;
|
table_rv = cstmt->relation;
|
||||||
|
@ -1185,9 +1189,27 @@ ProcessUtilitySlow(ParseState *pstate,
|
||||||
validnsps,
|
validnsps,
|
||||||
true,
|
true,
|
||||||
false);
|
false);
|
||||||
(void) heap_reloptions(RELKIND_TOASTVALUE,
|
|
||||||
toast_options,
|
/*
|
||||||
true);
|
* Get toast table AM to validate its options.
|
||||||
|
* Only relevant if table itself has a table AM.
|
||||||
|
* We don't need to place the lock given that
|
||||||
|
* DefineRelation() already placed the
|
||||||
|
* AccessExclusiveLock.
|
||||||
|
*/
|
||||||
|
rel = relation_open(address.objectId, NoLock);
|
||||||
|
accessMethodId = rel->rd_tableam ?
|
||||||
|
table_relation_toast_am(rel) : InvalidOid;
|
||||||
|
relation_close(rel, NoLock);
|
||||||
|
|
||||||
|
if (OidIsValid(accessMethodId))
|
||||||
|
{
|
||||||
|
tableam = GetTableAmRoutineByAmOid(accessMethodId);
|
||||||
|
(void) tableam_reloptions(tableam, RELKIND_TOASTVALUE,
|
||||||
|
toast_options,
|
||||||
|
NULL,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
NewRelationCreateToastTable(address.objectId,
|
NewRelationCreateToastTable(address.objectId,
|
||||||
toast_options);
|
toast_options);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/multixact.h"
|
#include "access/multixact.h"
|
||||||
#include "access/parallel.h"
|
#include "access/parallel.h"
|
||||||
|
#include "access/relation.h"
|
||||||
#include "access/reloptions.h"
|
#include "access/reloptions.h"
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "access/table.h"
|
#include "access/table.h"
|
||||||
|
@ -464,9 +465,48 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
|
||||||
{
|
{
|
||||||
bytea *options;
|
bytea *options;
|
||||||
amoptions_function amoptsfn;
|
amoptions_function amoptsfn;
|
||||||
|
CommonRdOptions *common = NULL;
|
||||||
|
const TableAmRoutine *tableam = NULL;
|
||||||
|
|
||||||
relation->rd_options = NULL;
|
relation->rd_options = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill the rd_common_options with default values for appropriate
|
||||||
|
* relkinds. The values might be later changed by extractRelOptions().
|
||||||
|
*/
|
||||||
|
if (relation->rd_rel->relkind == RELKIND_RELATION ||
|
||||||
|
relation->rd_rel->relkind == RELKIND_TOASTVALUE ||
|
||||||
|
relation->rd_rel->relkind == RELKIND_MATVIEW)
|
||||||
|
{
|
||||||
|
common = MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(CommonRdOptions));
|
||||||
|
common->autovacuum.enabled = true;
|
||||||
|
common->autovacuum.vacuum_threshold = -1;
|
||||||
|
common->autovacuum.vacuum_ins_threshold = -2;
|
||||||
|
common->autovacuum.analyze_threshold = -1;
|
||||||
|
common->autovacuum.vacuum_cost_limit = -1;
|
||||||
|
common->autovacuum.freeze_min_age = -1;
|
||||||
|
common->autovacuum.freeze_max_age = -1;
|
||||||
|
common->autovacuum.freeze_table_age = -1;
|
||||||
|
common->autovacuum.multixact_freeze_min_age = -1;
|
||||||
|
common->autovacuum.multixact_freeze_max_age = -1;
|
||||||
|
common->autovacuum.multixact_freeze_table_age = -1;
|
||||||
|
common->autovacuum.log_min_duration = -1;
|
||||||
|
common->autovacuum.vacuum_cost_delay = -1;
|
||||||
|
common->autovacuum.vacuum_scale_factor = -1;
|
||||||
|
common->autovacuum.vacuum_ins_scale_factor = -1;
|
||||||
|
common->autovacuum.analyze_scale_factor = -1;
|
||||||
|
common->parallel_workers = -1;
|
||||||
|
common->user_catalog_table = false;
|
||||||
|
common->vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
|
||||||
|
common->vacuum_truncate = true;
|
||||||
|
relation->rd_common_options = common;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
relation->rd_common_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up any AM-specific parse function; fall out if relkind should not
|
* Look up any AM-specific parse function; fall out if relkind should not
|
||||||
* have options.
|
* have options.
|
||||||
|
@ -478,6 +518,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
|
||||||
case RELKIND_VIEW:
|
case RELKIND_VIEW:
|
||||||
case RELKIND_MATVIEW:
|
case RELKIND_MATVIEW:
|
||||||
case RELKIND_PARTITIONED_TABLE:
|
case RELKIND_PARTITIONED_TABLE:
|
||||||
|
tableam = relation->rd_tableam;
|
||||||
amoptsfn = NULL;
|
amoptsfn = NULL;
|
||||||
break;
|
break;
|
||||||
case RELKIND_INDEX:
|
case RELKIND_INDEX:
|
||||||
|
@ -493,7 +534,8 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
|
||||||
* we might not have any other for pg_class yet (consider executing this
|
* we might not have any other for pg_class yet (consider executing this
|
||||||
* code for pg_class itself)
|
* code for pg_class itself)
|
||||||
*/
|
*/
|
||||||
options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
|
options = extractRelOptions(tuple, GetPgClassDescriptor(),
|
||||||
|
tableam, amoptsfn, common);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy parsed data into CacheMemoryContext. To guard against the
|
* Copy parsed data into CacheMemoryContext. To guard against the
|
||||||
|
@ -2300,6 +2342,8 @@ RelationReloadIndexInfo(Relation relation)
|
||||||
/* Reload reloptions in case they changed */
|
/* Reload reloptions in case they changed */
|
||||||
if (relation->rd_options)
|
if (relation->rd_options)
|
||||||
pfree(relation->rd_options);
|
pfree(relation->rd_options);
|
||||||
|
if (relation->rd_common_options)
|
||||||
|
pfree(relation->rd_common_options);
|
||||||
RelationParseRelOptions(relation, pg_class_tuple);
|
RelationParseRelOptions(relation, pg_class_tuple);
|
||||||
/* done with pg_class tuple */
|
/* done with pg_class tuple */
|
||||||
heap_freetuple(pg_class_tuple);
|
heap_freetuple(pg_class_tuple);
|
||||||
|
@ -2487,6 +2531,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
|
||||||
pfree(relation->rd_pubdesc);
|
pfree(relation->rd_pubdesc);
|
||||||
if (relation->rd_options)
|
if (relation->rd_options)
|
||||||
pfree(relation->rd_options);
|
pfree(relation->rd_options);
|
||||||
|
if (relation->rd_common_options)
|
||||||
|
pfree(relation->rd_common_options);
|
||||||
if (relation->rd_indextuple)
|
if (relation->rd_indextuple)
|
||||||
pfree(relation->rd_indextuple);
|
pfree(relation->rd_indextuple);
|
||||||
table_free_rd_amcache(relation);
|
table_free_rd_amcache(relation);
|
||||||
|
@ -4226,6 +4272,8 @@ RelationCacheInitializePhase3(void)
|
||||||
/* Update rd_options while we have the tuple */
|
/* Update rd_options while we have the tuple */
|
||||||
if (relation->rd_options)
|
if (relation->rd_options)
|
||||||
pfree(relation->rd_options);
|
pfree(relation->rd_options);
|
||||||
|
if (relation->rd_common_options)
|
||||||
|
pfree(relation->rd_common_options);
|
||||||
RelationParseRelOptions(relation, htup);
|
RelationParseRelOptions(relation, htup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6162,7 +6210,7 @@ load_relcache_init_file(bool shared)
|
||||||
has_not_null |= attr->attnotnull;
|
has_not_null |= attr->attnotnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* next read the access method specific field */
|
/* next read the access method specific fields */
|
||||||
if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
|
if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
|
||||||
goto read_failed;
|
goto read_failed;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
|
@ -6178,6 +6226,21 @@ load_relcache_init_file(bool shared)
|
||||||
rel->rd_options = NULL;
|
rel->rd_options = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
|
||||||
|
goto read_failed;
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
if (len != sizeof(CommonRdOptions))
|
||||||
|
goto read_failed;
|
||||||
|
rel->rd_common_options = palloc(len);
|
||||||
|
if (fread(rel->rd_common_options, 1, len, fp) != len)
|
||||||
|
goto read_failed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rel->rd_common_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* mark not-null status */
|
/* mark not-null status */
|
||||||
if (has_not_null)
|
if (has_not_null)
|
||||||
{
|
{
|
||||||
|
@ -6579,11 +6642,15 @@ write_relcache_init_file(bool shared)
|
||||||
ATTRIBUTE_FIXED_PART_SIZE, fp);
|
ATTRIBUTE_FIXED_PART_SIZE, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* next, do the access method specific field */
|
/* next, do the access method specific fields */
|
||||||
write_item(rel->rd_options,
|
write_item(rel->rd_options,
|
||||||
(rel->rd_options ? VARSIZE(rel->rd_options) : 0),
|
(rel->rd_options ? VARSIZE(rel->rd_options) : 0),
|
||||||
fp);
|
fp);
|
||||||
|
|
||||||
|
write_item(rel->rd_common_options,
|
||||||
|
(rel->rd_common_options ? sizeof(CommonRdOptions) : 0),
|
||||||
|
fp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's an index, there's more to do. Note we explicitly ignore
|
* If it's an index, there's more to do. Note we explicitly ignore
|
||||||
* partitioned indexes here.
|
* partitioned indexes here.
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "access/amapi.h"
|
#include "access/amapi.h"
|
||||||
#include "access/htup.h"
|
#include "access/htup.h"
|
||||||
|
#include "access/tableam.h"
|
||||||
#include "access/tupdesc.h"
|
#include "access/tupdesc.h"
|
||||||
#include "nodes/pg_list.h"
|
#include "nodes/pg_list.h"
|
||||||
#include "storage/lock.h"
|
#include "storage/lock.h"
|
||||||
|
@ -224,7 +225,9 @@ extern Datum transformRelOptions(Datum oldOptions, List *defList,
|
||||||
bool acceptOidsOff, bool isReset);
|
bool acceptOidsOff, bool isReset);
|
||||||
extern List *untransformRelOptions(Datum options);
|
extern List *untransformRelOptions(Datum options);
|
||||||
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
|
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
|
||||||
amoptions_function amoptions);
|
const TableAmRoutine *tableam,
|
||||||
|
amoptions_function amoptions,
|
||||||
|
CommonRdOptions *common);
|
||||||
extern void *build_reloptions(Datum reloptions, bool validate,
|
extern void *build_reloptions(Datum reloptions, bool validate,
|
||||||
relopt_kind kind,
|
relopt_kind kind,
|
||||||
Size relopt_struct_size,
|
Size relopt_struct_size,
|
||||||
|
@ -233,9 +236,8 @@ extern void *build_reloptions(Datum reloptions, bool validate,
|
||||||
extern void *build_local_reloptions(local_relopts *relopts, Datum options,
|
extern void *build_local_reloptions(local_relopts *relopts, Datum options,
|
||||||
bool validate);
|
bool validate);
|
||||||
|
|
||||||
extern bytea *default_reloptions(Datum reloptions, bool validate,
|
extern bytea *heap_reloptions(char relkind, Datum reloptions,
|
||||||
relopt_kind kind);
|
CommonRdOptions *common, bool validate);
|
||||||
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
|
|
||||||
extern bytea *view_reloptions(Datum reloptions, bool validate);
|
extern bytea *view_reloptions(Datum reloptions, bool validate);
|
||||||
extern bytea *partitioned_table_reloptions(Datum reloptions, bool validate);
|
extern bytea *partitioned_table_reloptions(Datum reloptions, bool validate);
|
||||||
extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
|
extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
|
||||||
|
|
|
@ -746,6 +746,34 @@ typedef struct TableAmRoutine
|
||||||
int32 slicelength,
|
int32 slicelength,
|
||||||
struct varlena *result);
|
struct varlena *result);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This callback parses and validates the reloptions array for a table.
|
||||||
|
*
|
||||||
|
* This is called only when a non-null reloptions array exists for the
|
||||||
|
* table. 'reloptions' is a text array containing entries of the form
|
||||||
|
* "name=value". The function should construct a bytea value, which will
|
||||||
|
* be copied into the rd_options field of the table's relcache entry. The
|
||||||
|
* data contents of the bytea value are open for the access method to
|
||||||
|
* define.
|
||||||
|
*
|
||||||
|
* The '*common' represents the common values, which the table access
|
||||||
|
* method exposes for autovacuum, query planner, and others. The caller
|
||||||
|
* should fill them with default values. The table access method may
|
||||||
|
* modify them on the base of options specified by a user.
|
||||||
|
*
|
||||||
|
* When 'validate' is true, the function should report a suitable error
|
||||||
|
* message if any of the options are unrecognized or have invalid values;
|
||||||
|
* when 'validate' is false, invalid entries should be silently ignored.
|
||||||
|
* ('validate' is false when loading options already stored in pg_catalog;
|
||||||
|
* an invalid entry could only be found if the access method has changed
|
||||||
|
* its rules for options, and in that case ignoring obsolete entries is
|
||||||
|
* appropriate.)
|
||||||
|
*
|
||||||
|
* It is OK to return NULL if default behavior is wanted.
|
||||||
|
*/
|
||||||
|
bytea *(*reloptions) (char relkind, Datum reloptions,
|
||||||
|
CommonRdOptions *common, bool validate);
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------
|
||||||
* Planner related functions.
|
* Planner related functions.
|
||||||
|
@ -1945,6 +1973,27 @@ table_relation_fetch_toast_slice(Relation toastrel, Oid valueid,
|
||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse table options without knowledge of particular table.
|
||||||
|
*/
|
||||||
|
static inline bytea *
|
||||||
|
tableam_reloptions(const TableAmRoutine *tableam, char relkind,
|
||||||
|
Datum reloptions, CommonRdOptions *common, bool validate)
|
||||||
|
{
|
||||||
|
return tableam->reloptions(relkind, reloptions, common, validate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse options for given table.
|
||||||
|
*/
|
||||||
|
static inline bytea *
|
||||||
|
table_reloptions(Relation rel, char relkind,
|
||||||
|
Datum reloptions, CommonRdOptions *common, bool validate)
|
||||||
|
{
|
||||||
|
return tableam_reloptions(rel->rd_tableam, relkind, reloptions,
|
||||||
|
common, validate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Planner related functionality
|
* Planner related functionality
|
||||||
|
@ -2123,6 +2172,7 @@ extern void table_block_relation_estimate_size(Relation rel,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern const TableAmRoutine *GetTableAmRoutine(Oid amhandler);
|
extern const TableAmRoutine *GetTableAmRoutine(Oid amhandler);
|
||||||
|
extern const TableAmRoutine *GetTableAmRoutineByAmOid(Oid amoid);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Functions in heapam_handler.c
|
* Functions in heapam_handler.c
|
||||||
|
|
|
@ -48,6 +48,52 @@ typedef struct LockInfoData
|
||||||
|
|
||||||
typedef LockInfoData *LockInfo;
|
typedef LockInfoData *LockInfo;
|
||||||
|
|
||||||
|
/* autovacuum-related reloptions. */
|
||||||
|
typedef struct AutoVacOpts
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
|
int vacuum_threshold;
|
||||||
|
int vacuum_ins_threshold;
|
||||||
|
int analyze_threshold;
|
||||||
|
int vacuum_cost_limit;
|
||||||
|
int freeze_min_age;
|
||||||
|
int freeze_max_age;
|
||||||
|
int freeze_table_age;
|
||||||
|
int multixact_freeze_min_age;
|
||||||
|
int multixact_freeze_max_age;
|
||||||
|
int multixact_freeze_table_age;
|
||||||
|
int log_min_duration;
|
||||||
|
float8 vacuum_cost_delay;
|
||||||
|
float8 vacuum_scale_factor;
|
||||||
|
float8 vacuum_ins_scale_factor;
|
||||||
|
float8 analyze_scale_factor;
|
||||||
|
} AutoVacOpts;
|
||||||
|
|
||||||
|
/* StdRdOptions->vacuum_index_cleanup values */
|
||||||
|
typedef enum StdRdOptIndexCleanup
|
||||||
|
{
|
||||||
|
STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0,
|
||||||
|
STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF,
|
||||||
|
STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON,
|
||||||
|
} StdRdOptIndexCleanup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CommonRdOptions
|
||||||
|
* Contents of rd_common_options for tables. It contains the options,
|
||||||
|
* which the table access method exposes for autovacuum, query planner,
|
||||||
|
* and others. These options could be by decision of table AM directly
|
||||||
|
* specified by a user or calculated in some way.
|
||||||
|
*/
|
||||||
|
typedef struct CommonRdOptions
|
||||||
|
{
|
||||||
|
AutoVacOpts autovacuum; /* autovacuum-related options */
|
||||||
|
bool user_catalog_table; /* use as an additional catalog relation */
|
||||||
|
int parallel_workers; /* max number of parallel workers */
|
||||||
|
StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */
|
||||||
|
bool vacuum_truncate; /* enables vacuum to truncate a relation */
|
||||||
|
} CommonRdOptions;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here are the contents of a relation cache entry.
|
* Here are the contents of a relation cache entry.
|
||||||
*/
|
*/
|
||||||
|
@ -168,11 +214,19 @@ typedef struct RelationData
|
||||||
PublicationDesc *rd_pubdesc; /* publication descriptor, or NULL */
|
PublicationDesc *rd_pubdesc; /* publication descriptor, or NULL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rd_options is set whenever rd_rel is loaded into the relcache entry.
|
* rd_options and rd_common_options are set whenever rd_rel is loaded into
|
||||||
* Note that you can NOT look into rd_rel for this data. NULL means "use
|
* the relcache entry. Note that you can NOT look into rd_rel for this
|
||||||
* defaults".
|
* data. NULLs means "use defaults".
|
||||||
*/
|
*/
|
||||||
bytea *rd_options; /* parsed pg_class.reloptions */
|
CommonRdOptions *rd_common_options; /* the options, which table AM exposes
|
||||||
|
* for external usage */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* am-specific part of pg_class.reloptions parsed by table am specific
|
||||||
|
* structure (e.g. struct HeapRdOptions) Contents are not to be accessed
|
||||||
|
* outside of table am
|
||||||
|
*/
|
||||||
|
bytea *rd_options;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Oid of the handler for this relation. For an index this is a function
|
* Oid of the handler for this relation. For an index this is a function
|
||||||
|
@ -297,88 +351,42 @@ typedef struct ForeignKeyCacheInfo
|
||||||
Oid conpfeqop[INDEX_MAX_KEYS] pg_node_attr(array_size(nkeys));
|
Oid conpfeqop[INDEX_MAX_KEYS] pg_node_attr(array_size(nkeys));
|
||||||
} ForeignKeyCacheInfo;
|
} ForeignKeyCacheInfo;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* StdRdOptions
|
* HeapRdOptions
|
||||||
* Standard contents of rd_options for heaps.
|
* Contents of rd_options specific for heap tables.
|
||||||
*
|
|
||||||
* RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only
|
|
||||||
* be applied to relations that use this format or a superset for
|
|
||||||
* private options data.
|
|
||||||
*/
|
*/
|
||||||
/* autovacuum-related reloptions. */
|
typedef struct HeapRdOptions
|
||||||
typedef struct AutoVacOpts
|
|
||||||
{
|
|
||||||
bool enabled;
|
|
||||||
int vacuum_threshold;
|
|
||||||
int vacuum_ins_threshold;
|
|
||||||
int analyze_threshold;
|
|
||||||
int vacuum_cost_limit;
|
|
||||||
int freeze_min_age;
|
|
||||||
int freeze_max_age;
|
|
||||||
int freeze_table_age;
|
|
||||||
int multixact_freeze_min_age;
|
|
||||||
int multixact_freeze_max_age;
|
|
||||||
int multixact_freeze_table_age;
|
|
||||||
int log_min_duration;
|
|
||||||
float8 vacuum_cost_delay;
|
|
||||||
float8 vacuum_scale_factor;
|
|
||||||
float8 vacuum_ins_scale_factor;
|
|
||||||
float8 analyze_scale_factor;
|
|
||||||
} AutoVacOpts;
|
|
||||||
|
|
||||||
/* StdRdOptions->vacuum_index_cleanup values */
|
|
||||||
typedef enum StdRdOptIndexCleanup
|
|
||||||
{
|
|
||||||
STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0,
|
|
||||||
STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF,
|
|
||||||
STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON,
|
|
||||||
} StdRdOptIndexCleanup;
|
|
||||||
|
|
||||||
typedef struct StdRdOptions
|
|
||||||
{
|
{
|
||||||
int32 vl_len_; /* varlena header (do not touch directly!) */
|
int32 vl_len_; /* varlena header (do not touch directly!) */
|
||||||
|
CommonRdOptions common;
|
||||||
int fillfactor; /* page fill factor in percent (0..100) */
|
int fillfactor; /* page fill factor in percent (0..100) */
|
||||||
int toast_tuple_target; /* target for tuple toasting */
|
int toast_tuple_target; /* target for tuple toasting */
|
||||||
AutoVacOpts autovacuum; /* autovacuum-related options */
|
} HeapRdOptions;
|
||||||
bool user_catalog_table; /* use as an additional catalog relation */
|
|
||||||
int parallel_workers; /* max number of parallel workers */
|
|
||||||
StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */
|
|
||||||
bool vacuum_truncate; /* enables vacuum to truncate a relation */
|
|
||||||
} StdRdOptions;
|
|
||||||
|
|
||||||
#define HEAP_MIN_FILLFACTOR 10
|
#define HEAP_MIN_FILLFACTOR 10
|
||||||
#define HEAP_DEFAULT_FILLFACTOR 100
|
#define HEAP_DEFAULT_FILLFACTOR 100
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationGetToastTupleTarget
|
* HeapGetFillFactor
|
||||||
* Returns the relation's toast_tuple_target. Note multiple eval of argument!
|
* Returns the heap relation's fillfactor. Note multiple eval of argument!
|
||||||
*/
|
*/
|
||||||
#define RelationGetToastTupleTarget(relation, defaulttarg) \
|
#define HeapGetFillFactor(relation, defaultff) \
|
||||||
((relation)->rd_options ? \
|
((relation)->rd_options ? \
|
||||||
((StdRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
|
((HeapRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationGetFillFactor
|
* HeapGetTargetPageUsage
|
||||||
* Returns the relation's fillfactor. Note multiple eval of argument!
|
|
||||||
*/
|
|
||||||
#define RelationGetFillFactor(relation, defaultff) \
|
|
||||||
((relation)->rd_options ? \
|
|
||||||
((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RelationGetTargetPageUsage
|
|
||||||
* Returns the relation's desired space usage per page in bytes.
|
* Returns the relation's desired space usage per page in bytes.
|
||||||
*/
|
*/
|
||||||
#define RelationGetTargetPageUsage(relation, defaultff) \
|
#define HeapGetTargetPageUsage(relation, defaultff) \
|
||||||
(BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100)
|
(BLCKSZ * HeapGetFillFactor(relation, defaultff) / 100)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationGetTargetPageFreeSpace
|
* HeapGetTargetPageFreeSpace
|
||||||
* Returns the relation's desired freespace per page in bytes.
|
* Returns the relation's desired freespace per page in bytes.
|
||||||
*/
|
*/
|
||||||
#define RelationGetTargetPageFreeSpace(relation, defaultff) \
|
#define HeapGetTargetPageFreeSpace(relation, defaultff) \
|
||||||
(BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100)
|
(BLCKSZ * (100 - HeapGetFillFactor(relation, defaultff)) / 100)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationIsUsedAsCatalogTable
|
* RelationIsUsedAsCatalogTable
|
||||||
|
@ -386,10 +394,10 @@ typedef struct StdRdOptions
|
||||||
* from the pov of logical decoding. Note multiple eval of argument!
|
* from the pov of logical decoding. Note multiple eval of argument!
|
||||||
*/
|
*/
|
||||||
#define RelationIsUsedAsCatalogTable(relation) \
|
#define RelationIsUsedAsCatalogTable(relation) \
|
||||||
((relation)->rd_options && \
|
((relation)->rd_common_options && \
|
||||||
((relation)->rd_rel->relkind == RELKIND_RELATION || \
|
((relation)->rd_rel->relkind == RELKIND_RELATION || \
|
||||||
(relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \
|
(relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \
|
||||||
((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false)
|
(relation)->rd_common_options->user_catalog_table : false)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationGetParallelWorkers
|
* RelationGetParallelWorkers
|
||||||
|
@ -397,8 +405,8 @@ typedef struct StdRdOptions
|
||||||
* Note multiple eval of argument!
|
* Note multiple eval of argument!
|
||||||
*/
|
*/
|
||||||
#define RelationGetParallelWorkers(relation, defaultpw) \
|
#define RelationGetParallelWorkers(relation, defaultpw) \
|
||||||
((relation)->rd_options ? \
|
((relation)->rd_common_options ? \
|
||||||
((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw))
|
(relation)->rd_common_options->parallel_workers : (defaultpw))
|
||||||
|
|
||||||
/* ViewOptions->check_option values */
|
/* ViewOptions->check_option values */
|
||||||
typedef enum ViewOptCheckOption
|
typedef enum ViewOptCheckOption
|
||||||
|
|
|
@ -36,6 +36,7 @@ SUBDIRS = \
|
||||||
test_rls_hooks \
|
test_rls_hooks \
|
||||||
test_shm_mq \
|
test_shm_mq \
|
||||||
test_slru \
|
test_slru \
|
||||||
|
test_tam_options \
|
||||||
test_tidstore \
|
test_tidstore \
|
||||||
unsafe_tests \
|
unsafe_tests \
|
||||||
worker_spi \
|
worker_spi \
|
||||||
|
|
|
@ -35,6 +35,7 @@ subdir('test_resowner')
|
||||||
subdir('test_rls_hooks')
|
subdir('test_rls_hooks')
|
||||||
subdir('test_shm_mq')
|
subdir('test_shm_mq')
|
||||||
subdir('test_slru')
|
subdir('test_slru')
|
||||||
|
subdir('test_tam_options')
|
||||||
subdir('test_tidstore')
|
subdir('test_tidstore')
|
||||||
subdir('unsafe_tests')
|
subdir('unsafe_tests')
|
||||||
subdir('worker_spi')
|
subdir('worker_spi')
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Generated subdirectories
|
||||||
|
/log/
|
||||||
|
/results/
|
||||||
|
/tmp_check/
|
|
@ -0,0 +1,23 @@
|
||||||
|
# src/test/modules/test_tam_options/Makefile
|
||||||
|
|
||||||
|
MODULE_big = test_tam_options
|
||||||
|
OBJS = \
|
||||||
|
$(WIN32RES) \
|
||||||
|
test_tam_options.o
|
||||||
|
PGFILEDESC = "test_tam_options - test code for table access method reloptions"
|
||||||
|
|
||||||
|
EXTENSION = test_tam_options
|
||||||
|
DATA = test_tam_options--1.0.sql
|
||||||
|
|
||||||
|
REGRESS = test_tam_options
|
||||||
|
|
||||||
|
ifdef USE_PGXS
|
||||||
|
PG_CONFIG = pg_config
|
||||||
|
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||||
|
include $(PGXS)
|
||||||
|
else
|
||||||
|
subdir = src/test/modules/test_tam_options
|
||||||
|
top_builddir = ../../../..
|
||||||
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
include $(top_srcdir)/contrib/contrib-global.mk
|
||||||
|
endif
|
|
@ -0,0 +1,36 @@
|
||||||
|
CREATE EXTENSION test_tam_options;
|
||||||
|
-- encourage use of parallel plans
|
||||||
|
SET parallel_setup_cost = 0;
|
||||||
|
SET parallel_tuple_cost = 0;
|
||||||
|
SET min_parallel_table_scan_size = 0;
|
||||||
|
SET max_parallel_workers_per_gather = 4;
|
||||||
|
CREATE TABLE test (i int) USING heap_alter_options;
|
||||||
|
INSERT INTO test SELECT i FROM generate_series(1, 10000) i;
|
||||||
|
VACUUM ANALYZE test;
|
||||||
|
EXPLAIN (costs off)
|
||||||
|
SELECT * FROM test;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------
|
||||||
|
Gather
|
||||||
|
Workers Planned: 4
|
||||||
|
-> Parallel Seq Scan on test
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
ALTER TABLE test SET (enable_parallel = OFF);
|
||||||
|
EXPLAIN (costs off)
|
||||||
|
SELECT * FROM test;
|
||||||
|
QUERY PLAN
|
||||||
|
------------------
|
||||||
|
Seq Scan on test
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ALTER TABLE test SET (enable_parallel = ON);
|
||||||
|
EXPLAIN (costs off)
|
||||||
|
SELECT * FROM test;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------
|
||||||
|
Gather
|
||||||
|
Workers Planned: 4
|
||||||
|
-> Parallel Seq Scan on test
|
||||||
|
(3 rows)
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Copyright (c) 2024, PostgreSQL Global Development Group
|
||||||
|
|
||||||
|
test_tam_options_sources = files(
|
||||||
|
'test_tam_options.c',
|
||||||
|
)
|
||||||
|
|
||||||
|
if host_system == 'windows'
|
||||||
|
test_tam_options_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
|
||||||
|
'--NAME', 'test_tam_options',
|
||||||
|
'--FILEDESC', 'test_tam_options - test code for table access method reloptions',])
|
||||||
|
endif
|
||||||
|
|
||||||
|
test_tam_options = shared_module('test_tam_options',
|
||||||
|
test_tam_options_sources,
|
||||||
|
kwargs: pg_test_mod_args,
|
||||||
|
)
|
||||||
|
test_install_libs += test_tam_options
|
||||||
|
|
||||||
|
test_install_data += files(
|
||||||
|
'test_tam_options.control',
|
||||||
|
'test_tam_options--1.0.sql',
|
||||||
|
)
|
||||||
|
|
||||||
|
tests += {
|
||||||
|
'name': 'test_tam_options',
|
||||||
|
'sd': meson.current_source_dir(),
|
||||||
|
'bd': meson.current_build_dir(),
|
||||||
|
'regress': {
|
||||||
|
'sql': [
|
||||||
|
'test_tam_options',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
CREATE EXTENSION test_tam_options;
|
||||||
|
|
||||||
|
-- encourage use of parallel plans
|
||||||
|
SET parallel_setup_cost = 0;
|
||||||
|
SET parallel_tuple_cost = 0;
|
||||||
|
SET min_parallel_table_scan_size = 0;
|
||||||
|
SET max_parallel_workers_per_gather = 4;
|
||||||
|
|
||||||
|
CREATE TABLE test (i int) USING heap_alter_options;
|
||||||
|
|
||||||
|
INSERT INTO test SELECT i FROM generate_series(1, 10000) i;
|
||||||
|
VACUUM ANALYZE test;
|
||||||
|
|
||||||
|
EXPLAIN (costs off)
|
||||||
|
SELECT * FROM test;
|
||||||
|
|
||||||
|
ALTER TABLE test SET (enable_parallel = OFF);
|
||||||
|
|
||||||
|
EXPLAIN (costs off)
|
||||||
|
SELECT * FROM test;
|
||||||
|
|
||||||
|
ALTER TABLE test SET (enable_parallel = ON);
|
||||||
|
|
||||||
|
EXPLAIN (costs off)
|
||||||
|
SELECT * FROM test;
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* src/test/modules/test_tam_options/test_tam_options--1.0.sql */
|
||||||
|
|
||||||
|
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
|
\echo Use "CREATE EXTENSION test_tam_options" to load this file. \quit
|
||||||
|
|
||||||
|
CREATE FUNCTION heap_alter_options_tam_handler(internal)
|
||||||
|
RETURNS table_am_handler
|
||||||
|
AS 'MODULE_PATHNAME'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
|
||||||
|
CREATE ACCESS METHOD heap_alter_options TYPE TABLE
|
||||||
|
HANDLER heap_alter_options_tam_handler;
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* test_tam_options.c
|
||||||
|
* Test code for table access method reloptions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* src/test/modules/test_tam_options/test_tam_options.c
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/reloptions.h"
|
||||||
|
#include "access/tableam.h"
|
||||||
|
|
||||||
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(heap_alter_options_tam_handler);
|
||||||
|
|
||||||
|
/* An alternative relation options for heap */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int32 vl_len_; /* varlena header (do not touch directly!) */
|
||||||
|
bool enable_parallel; /* enable parallel scans? */
|
||||||
|
} HeapAlterRdOptions;
|
||||||
|
|
||||||
|
static bytea *
|
||||||
|
heap_alter_reloptions(char relkind, Datum reloptions,
|
||||||
|
CommonRdOptions *common, bool validate)
|
||||||
|
{
|
||||||
|
local_relopts relopts;
|
||||||
|
HeapAlterRdOptions *result;
|
||||||
|
|
||||||
|
Assert(relkind == RELKIND_RELATION ||
|
||||||
|
relkind == RELKIND_TOASTVALUE ||
|
||||||
|
relkind == RELKIND_MATVIEW);
|
||||||
|
|
||||||
|
init_local_reloptions(&relopts, sizeof(HeapAlterRdOptions));
|
||||||
|
add_local_bool_reloption(&relopts, "enable_parallel",
|
||||||
|
"enable parallel scan", true,
|
||||||
|
offsetof(HeapAlterRdOptions, enable_parallel));
|
||||||
|
|
||||||
|
result = (HeapAlterRdOptions *) build_local_reloptions(&relopts,
|
||||||
|
reloptions,
|
||||||
|
validate);
|
||||||
|
|
||||||
|
if (result != NULL && common != NULL)
|
||||||
|
{
|
||||||
|
common->parallel_workers = result->enable_parallel ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bytea *) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
heap_alter_options_tam_handler(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
static TableAmRoutine tam_routine;
|
||||||
|
|
||||||
|
tam_routine = *GetHeapamTableAmRoutine();
|
||||||
|
tam_routine.reloptions = heap_alter_reloptions;
|
||||||
|
|
||||||
|
PG_RETURN_POINTER(&tam_routine);
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
comment = 'Test code for table access method reloptions'
|
||||||
|
default_version = '1.0'
|
||||||
|
module_pathname = '$libdir/test_tam_options'
|
||||||
|
relocatable = true
|
|
@ -442,6 +442,7 @@ CommentStmt
|
||||||
CommitTimestampEntry
|
CommitTimestampEntry
|
||||||
CommitTimestampShared
|
CommitTimestampShared
|
||||||
CommonEntry
|
CommonEntry
|
||||||
|
CommonRdOptions
|
||||||
CommonTableExpr
|
CommonTableExpr
|
||||||
CompareScalarsContext
|
CompareScalarsContext
|
||||||
CompiledExprState
|
CompiledExprState
|
||||||
|
@ -1129,8 +1130,10 @@ HbaLine
|
||||||
HeadlineJsonState
|
HeadlineJsonState
|
||||||
HeadlineParsedText
|
HeadlineParsedText
|
||||||
HeadlineWordEntry
|
HeadlineWordEntry
|
||||||
|
HeapAlterRdOptions
|
||||||
HeapCheckContext
|
HeapCheckContext
|
||||||
HeapPageFreeze
|
HeapPageFreeze
|
||||||
|
HeapRdOptions
|
||||||
HeapScanDesc
|
HeapScanDesc
|
||||||
HeapTuple
|
HeapTuple
|
||||||
HeapTupleData
|
HeapTupleData
|
||||||
|
@ -2723,7 +2726,6 @@ StatsElem
|
||||||
StatsExtInfo
|
StatsExtInfo
|
||||||
StdAnalyzeData
|
StdAnalyzeData
|
||||||
StdRdOptIndexCleanup
|
StdRdOptIndexCleanup
|
||||||
StdRdOptions
|
|
||||||
Step
|
Step
|
||||||
StopList
|
StopList
|
||||||
StrategyNumber
|
StrategyNumber
|
||||||
|
|
Loading…
Reference in New Issue