2019-09-25 05:11:12 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* dummy_index_am.c
|
|
|
|
* Index AM template main file.
|
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2019-09-25 05:11:12 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/test/modules/dummy_index_am/dummy_index_am.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2019-12-27 00:09:00 +01:00
|
|
|
#include "access/amapi.h"
|
2019-09-25 05:11:12 +02:00
|
|
|
#include "access/reloptions.h"
|
|
|
|
#include "catalog/index.h"
|
2020-01-15 02:54:14 +01:00
|
|
|
#include "commands/vacuum.h"
|
2019-09-25 05:11:12 +02:00
|
|
|
#include "nodes/pathnodes.h"
|
|
|
|
#include "utils/guc.h"
|
|
|
|
#include "utils/rel.h"
|
|
|
|
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
|
|
|
|
/* parse table for fillRelOptions */
|
2019-09-25 20:56:52 +02:00
|
|
|
relopt_parse_elt di_relopt_tab[6];
|
2019-09-25 05:11:12 +02:00
|
|
|
|
|
|
|
/* Kind of relation options for dummy index */
|
|
|
|
relopt_kind di_relopt_kind;
|
|
|
|
|
2019-09-25 20:56:52 +02:00
|
|
|
typedef enum DummyAmEnum
|
|
|
|
{
|
|
|
|
DUMMY_AM_ENUM_ONE,
|
|
|
|
DUMMY_AM_ENUM_TWO,
|
|
|
|
} DummyAmEnum;
|
|
|
|
|
2019-09-25 05:11:12 +02:00
|
|
|
/* Dummy index options */
|
|
|
|
typedef struct DummyIndexOptions
|
|
|
|
{
|
|
|
|
int32 vl_len_; /* varlena header (do not touch directly!) */
|
|
|
|
int option_int;
|
|
|
|
double option_real;
|
|
|
|
bool option_bool;
|
2019-09-25 20:56:52 +02:00
|
|
|
DummyAmEnum option_enum;
|
2019-09-25 05:11:12 +02:00
|
|
|
int option_string_val_offset;
|
|
|
|
int option_string_null_offset;
|
|
|
|
} DummyIndexOptions;
|
|
|
|
|
2019-09-25 20:56:52 +02:00
|
|
|
relopt_enum_elt_def dummyAmEnumValues[] =
|
|
|
|
{
|
|
|
|
{"one", DUMMY_AM_ENUM_ONE},
|
|
|
|
{"two", DUMMY_AM_ENUM_TWO},
|
|
|
|
{(const char *) NULL} /* list terminator */
|
|
|
|
};
|
|
|
|
|
2019-09-25 05:11:12 +02:00
|
|
|
/* Handler for index AM */
|
|
|
|
PG_FUNCTION_INFO_V1(dihandler);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validation function for string relation options.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
validate_string_option(const char *value)
|
|
|
|
{
|
|
|
|
ereport(NOTICE,
|
|
|
|
(errmsg("new option value for string parameter %s",
|
|
|
|
value ? value : "NULL")));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function creates a full set of relation option types,
|
|
|
|
* with various patterns.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
create_reloptions_table(void)
|
|
|
|
{
|
|
|
|
di_relopt_kind = add_reloption_kind();
|
|
|
|
|
|
|
|
add_int_reloption(di_relopt_kind, "option_int",
|
|
|
|
"Integer option for dummy_index_am",
|
|
|
|
10, -10, 100, AccessExclusiveLock);
|
|
|
|
di_relopt_tab[0].optname = "option_int";
|
|
|
|
di_relopt_tab[0].opttype = RELOPT_TYPE_INT;
|
|
|
|
di_relopt_tab[0].offset = offsetof(DummyIndexOptions, option_int);
|
|
|
|
|
|
|
|
add_real_reloption(di_relopt_kind, "option_real",
|
|
|
|
"Real option for dummy_index_am",
|
|
|
|
3.1415, -10, 100, AccessExclusiveLock);
|
|
|
|
di_relopt_tab[1].optname = "option_real";
|
|
|
|
di_relopt_tab[1].opttype = RELOPT_TYPE_REAL;
|
|
|
|
di_relopt_tab[1].offset = offsetof(DummyIndexOptions, option_real);
|
|
|
|
|
|
|
|
add_bool_reloption(di_relopt_kind, "option_bool",
|
|
|
|
"Boolean option for dummy_index_am",
|
|
|
|
true, AccessExclusiveLock);
|
|
|
|
di_relopt_tab[2].optname = "option_bool";
|
|
|
|
di_relopt_tab[2].opttype = RELOPT_TYPE_BOOL;
|
|
|
|
di_relopt_tab[2].offset = offsetof(DummyIndexOptions, option_bool);
|
|
|
|
|
2019-09-25 20:56:52 +02:00
|
|
|
add_enum_reloption(di_relopt_kind, "option_enum",
|
|
|
|
"Enum option for dummy_index_am",
|
|
|
|
dummyAmEnumValues,
|
|
|
|
DUMMY_AM_ENUM_ONE,
|
|
|
|
"Valid values are \"one\" and \"two\".",
|
|
|
|
AccessExclusiveLock);
|
|
|
|
di_relopt_tab[3].optname = "option_enum";
|
|
|
|
di_relopt_tab[3].opttype = RELOPT_TYPE_ENUM;
|
|
|
|
di_relopt_tab[3].offset = offsetof(DummyIndexOptions, option_enum);
|
|
|
|
|
2019-09-25 05:11:12 +02:00
|
|
|
add_string_reloption(di_relopt_kind, "option_string_val",
|
|
|
|
"String option for dummy_index_am with non-NULL default",
|
|
|
|
"DefaultValue", &validate_string_option,
|
|
|
|
AccessExclusiveLock);
|
2019-09-25 20:56:52 +02:00
|
|
|
di_relopt_tab[4].optname = "option_string_val";
|
|
|
|
di_relopt_tab[4].opttype = RELOPT_TYPE_STRING;
|
|
|
|
di_relopt_tab[4].offset = offsetof(DummyIndexOptions,
|
2019-09-25 05:11:12 +02:00
|
|
|
option_string_val_offset);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* String option for dummy_index_am with NULL default, and without
|
|
|
|
* description.
|
|
|
|
*/
|
|
|
|
add_string_reloption(di_relopt_kind, "option_string_null",
|
|
|
|
NULL, /* description */
|
|
|
|
NULL, &validate_string_option,
|
|
|
|
AccessExclusiveLock);
|
2019-09-25 20:56:52 +02:00
|
|
|
di_relopt_tab[5].optname = "option_string_null";
|
|
|
|
di_relopt_tab[5].opttype = RELOPT_TYPE_STRING;
|
|
|
|
di_relopt_tab[5].offset = offsetof(DummyIndexOptions,
|
2019-09-25 05:11:12 +02:00
|
|
|
option_string_null_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build a new index.
|
|
|
|
*/
|
|
|
|
static IndexBuildResult *
|
|
|
|
dibuild(Relation heap, Relation index, IndexInfo *indexInfo)
|
|
|
|
{
|
|
|
|
IndexBuildResult *result;
|
|
|
|
|
|
|
|
result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
|
|
|
|
|
|
|
|
/* let's pretend that no tuples were scanned */
|
|
|
|
result->heap_tuples = 0;
|
|
|
|
/* and no index tuples were created (that is true) */
|
|
|
|
result->index_tuples = 0;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-11-02 07:14:41 +01:00
|
|
|
* Build an empty index for the initialization fork.
|
2019-09-25 05:11:12 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dibuildempty(Relation index)
|
|
|
|
{
|
|
|
|
/* No need to build an init fork for a dummy index */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert new tuple to index AM.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
diinsert(Relation index, Datum *values, bool *isnull,
|
|
|
|
ItemPointer ht_ctid, Relation heapRel,
|
|
|
|
IndexUniqueCheck checkUnique,
|
2021-01-13 17:11:00 +01:00
|
|
|
bool indexUnchanged,
|
2019-09-25 05:11:12 +02:00
|
|
|
IndexInfo *indexInfo)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Bulk deletion of all index entries pointing to a set of table tuples.
|
|
|
|
*/
|
|
|
|
static IndexBulkDeleteResult *
|
|
|
|
dibulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
|
|
|
|
IndexBulkDeleteCallback callback, void *callback_state)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* There is nothing to delete. Return NULL as there is nothing to pass to
|
|
|
|
* amvacuumcleanup.
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Post-VACUUM cleanup for index AM.
|
|
|
|
*/
|
|
|
|
static IndexBulkDeleteResult *
|
|
|
|
divacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
|
|
|
|
{
|
|
|
|
/* Index has not been modified, so returning NULL is fine */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Estimate cost of index AM.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dicostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
|
|
|
|
Cost *indexStartupCost, Cost *indexTotalCost,
|
|
|
|
Selectivity *indexSelectivity, double *indexCorrelation,
|
|
|
|
double *indexPages)
|
|
|
|
{
|
|
|
|
/* Tell planner to never use this index! */
|
|
|
|
*indexStartupCost = 1.0e10;
|
|
|
|
*indexTotalCost = 1.0e10;
|
|
|
|
|
|
|
|
/* Do not care about the rest */
|
|
|
|
*indexSelectivity = 1;
|
|
|
|
*indexCorrelation = 0;
|
|
|
|
*indexPages = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse relation options for index AM, returning a DummyIndexOptions
|
|
|
|
* structure filled with option values.
|
|
|
|
*/
|
|
|
|
static bytea *
|
|
|
|
dioptions(Datum reloptions, bool validate)
|
|
|
|
{
|
2019-11-05 01:17:05 +01:00
|
|
|
return (bytea *) build_reloptions(reloptions, validate,
|
|
|
|
di_relopt_kind,
|
|
|
|
sizeof(DummyIndexOptions),
|
|
|
|
di_relopt_tab, lengthof(di_relopt_tab));
|
2019-09-25 05:11:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validator for index AM.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
divalidate(Oid opclassoid)
|
|
|
|
{
|
|
|
|
/* Index is dummy so we are happy with any opclass */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Begin scan of index AM.
|
|
|
|
*/
|
|
|
|
static IndexScanDesc
|
|
|
|
dibeginscan(Relation r, int nkeys, int norderbys)
|
|
|
|
{
|
|
|
|
IndexScanDesc scan;
|
|
|
|
|
|
|
|
/* Let's pretend we are doing something */
|
|
|
|
scan = RelationGetIndexScan(r, nkeys, norderbys);
|
|
|
|
return scan;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rescan of index AM.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
direscan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
|
|
|
|
ScanKey orderbys, int norderbys)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End scan of index AM.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
diendscan(IndexScanDesc scan)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Index AM handler function: returns IndexAmRoutine with access method
|
|
|
|
* parameters and callbacks.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dihandler(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
|
|
|
|
|
|
|
amroutine->amstrategies = 0;
|
|
|
|
amroutine->amsupport = 1;
|
|
|
|
amroutine->amcanorder = false;
|
|
|
|
amroutine->amcanorderbyop = false;
|
|
|
|
amroutine->amcanbackward = false;
|
|
|
|
amroutine->amcanunique = false;
|
|
|
|
amroutine->amcanmulticol = false;
|
|
|
|
amroutine->amoptionalkey = false;
|
|
|
|
amroutine->amsearcharray = false;
|
|
|
|
amroutine->amsearchnulls = false;
|
|
|
|
amroutine->amstorage = false;
|
|
|
|
amroutine->amclusterable = false;
|
|
|
|
amroutine->ampredlocks = false;
|
|
|
|
amroutine->amcanparallel = false;
|
Allow parallel CREATE INDEX for BRIN indexes
Allow using multiple worker processes to build BRIN index, which until
now was supported only for BTREE indexes. For large tables this often
results in significant speedup when the build is CPU-bound.
The work is split in a simple way - each worker builds BRIN summaries on
a subset of the table, determined by the regular parallel scan used to
read the data, and feeds them into a shared tuplesort which sorts them
by blkno (start of the range). The leader then reads this sorted stream
of ranges, merges duplicates (which may happen if the parallel scan does
not align with BRIN pages_per_range), and adds the resulting ranges into
the index.
The number of duplicate results produced by workers (requiring merging
in the leader process) should be fairly small, thanks to how parallel
scans assign chunks to workers. The likelihood of duplicate results may
increase for higher pages_per_range values, but then there are fewer
page ranges in total. In any case, we expect the merging to be much
cheaper than summarization, so this should be a win.
Most of the parallelism infrastructure is a simplified copy of the code
used by BTREE indexes, omitting the parts irrelevant for BRIN indexes
(e.g. uniqueness checks).
This also introduces a new index AM flag amcanbuildparallel, determining
whether to attempt to start parallel workers for the index build.
Original patch by me, with reviews and substantial reworks by Matthias
van de Meent, certainly enough to make him a co-author.
Author: Tomas Vondra, Matthias van de Meent
Reviewed-by: Matthias van de Meent
Discussion: https://postgr.es/m/c2ee7d69-ce17-43f2-d1a0-9811edbda6e6%40enterprisedb.com
2023-12-08 18:15:23 +01:00
|
|
|
amroutine->amcanbuildparallel = false;
|
2019-09-25 05:11:12 +02:00
|
|
|
amroutine->amcaninclude = false;
|
2020-01-15 02:54:14 +01:00
|
|
|
amroutine->amusemaintenanceworkmem = false;
|
Ignore BRIN indexes when checking for HOT updates
When determining whether an index update may be skipped by using HOT, we
can ignore attributes indexed by block summarizing indexes without
references to individual tuples that need to be cleaned up.
A new type TU_UpdateIndexes provides a signal to the executor to
determine which indexes to update - no indexes, all indexes, or only the
summarizing indexes.
This also removes rd_indexattr list, and replaces it with rd_attrsvalid
flag. The list was not used anywhere, and a simple flag is sufficient.
This was originally committed as 5753d4ee32, but then got reverted by
e3fcca0d0d because of correctness issues.
Original patch by Josef Simanek, various fixes and improvements by Tomas
Vondra and me.
Authors: Matthias van de Meent, Josef Simanek, Tomas Vondra
Reviewed-by: Tomas Vondra, Alvaro Herrera
Discussion: https://postgr.es/m/05ebcb44-f383-86e3-4f31-0a97a55634cf@enterprisedb.com
Discussion: https://postgr.es/m/CAFp7QwpMRGcDAQumN7onN9HjrJ3u4X3ZRXdGFT0K5G2JWvnbWg%40mail.gmail.com
2023-03-20 10:34:07 +01:00
|
|
|
amroutine->amsummarizing = false;
|
2020-01-15 02:54:14 +01:00
|
|
|
amroutine->amparallelvacuumoptions = VACUUM_OPTION_NO_PARALLEL;
|
2019-09-25 05:11:12 +02:00
|
|
|
amroutine->amkeytype = InvalidOid;
|
|
|
|
|
|
|
|
amroutine->ambuild = dibuild;
|
|
|
|
amroutine->ambuildempty = dibuildempty;
|
|
|
|
amroutine->aminsert = diinsert;
|
|
|
|
amroutine->ambulkdelete = dibulkdelete;
|
|
|
|
amroutine->amvacuumcleanup = divacuumcleanup;
|
|
|
|
amroutine->amcanreturn = NULL;
|
|
|
|
amroutine->amcostestimate = dicostestimate;
|
|
|
|
amroutine->amoptions = dioptions;
|
|
|
|
amroutine->amproperty = NULL;
|
|
|
|
amroutine->ambuildphasename = NULL;
|
|
|
|
amroutine->amvalidate = divalidate;
|
|
|
|
amroutine->ambeginscan = dibeginscan;
|
|
|
|
amroutine->amrescan = direscan;
|
|
|
|
amroutine->amgettuple = NULL;
|
|
|
|
amroutine->amgetbitmap = NULL;
|
|
|
|
amroutine->amendscan = diendscan;
|
|
|
|
amroutine->ammarkpos = NULL;
|
|
|
|
amroutine->amrestrpos = NULL;
|
|
|
|
amroutine->amestimateparallelscan = NULL;
|
|
|
|
amroutine->aminitparallelscan = NULL;
|
|
|
|
amroutine->amparallelrescan = NULL;
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(amroutine);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_PG_init(void)
|
|
|
|
{
|
|
|
|
create_reloptions_table();
|
|
|
|
}
|